Spring IoC依赖注入-6

news2024/11/26 10:29:05

1. 依赖注入的模式和模型: Spring 提供了哪些依赖注入的模式和类型?

  • 手动模式 - 配置或者编程的方式,提前安排注入规则

    • XML资源配置元信息
    • Java 注解配置元信息
    • API 配置元信息
  • 自动模式 - 实现方提供依赖自动关联的方式,按照内建的注入规则

    • Autowiring (自动绑定)
  • 依赖注入类型
    在这里插入图片描述

2. 自动绑定(Autowiring):为什么Spring会引入Autowiring?

  • 官方说明

    • The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.

      spring容器能够通过自动绑定的关系, 在所谓的合作Bean之间(意思就是依赖类/被依赖类), 通过检查ApplicationContext的内容, 让spring能去处理这些合作者Bean
  • 优点

    • Autowiring can significantly reduce the need to specify properties or constructor arguments.

      Autowiring 可以有效减少我们一些属性或构造器参数的一个设定
      
    • Autowiring can update a configuration as your objects evolve.

      自动绑定能更新配置, 就当你的对象正在被逐渐升级或逐渐形成的时候
      

3. 自动绑定(Autowiring)模式:各种自动绑定模式的使用场景是什么?

  • Autowiring modes

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2uOAbmv3-1669797885493)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221124162056276.png)]

    参考枚举: org.springframework. beans.factory.annotation.Autowire

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jp8xrNLT-1669797885494)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221124164442428.png)]

    为什么没有构造器模式, 因为构造器模式是一种特殊的BY_TYPE

4. 自动绑定(Autowiring)限制和不足:如何理解和挖掘官方文档中深层次的含义?

  • 官方说明

    • Limitations and Disadvantages of Autowiring

      • 链接: https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/spring-framework-reference/core.html#beans-autowired-exceptions

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddtYaJKU-1669797885494)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221124173313184.png)]

5. Setter方法依赖注入:Setter注入的原理是什么?

  • 实现方法

    • 手动模式

      • XML资源配置元信息

        • dependency-lookup-context.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          <!--    实施加载bean-->
              <bean id="user" class="org.xiaoge.thinking.in.spring.ioc.overview.domain.User">
                  <property name="id" value="1" />
                  <property name="name" value="xiaoge"/>
              </bean>
          
              <!-- 延迟bean 是沟通objectFactory简介创建的 -->
              <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
                  <property name="targetBeanName" value="user" />
              </bean>
          
              <!-- parent继承 -->
              <bean id="superUser" class="org.xiaoge.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user" primary="true">
                  <property name="address" value="武汉" />
              </bean>
          
          </beans>
          
        • dependency-setter-injection.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          
              <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
          
              <!--    setter依赖注入  -->
              <bean class="org.xiaoge.thinking.in.spring.ioc.dependency.injection.UserHolder">
                  <property name="user" ref="user"></property>
              </bean>
          
          </beans>
          
        • UserHolder.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          /**
           * {@link org.xiaoge.thinking.in.spring.ioc.overview.domain.User} Holder 类
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class UserHolder {
          
              private User user;
          
              public UserHolder() {
              }
              
              public UserHolder(User user) {
                  this.user = user;
              }
          
              public User getUser() {
                  return user;
              }
          
              public void setUser(User user) {
                  this.user = user;
              }
          
              @Override
              public String toString() {
                  return "UserHolder{" +
                          "user=" + user +
                          '}';
              }
          }
          
        • XmlDependencySetterInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.support.DefaultListableBeanFactory;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          
          /**
           * 基于 XML 资源的依赖 Setter 方法注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class XmlDependencySetterInjectionDemo {
          
              public static void main(String[] args) {
                  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          
                  String xmlSourcePath = "classpath:/META-INF/dependency-setter-injection.xml";
          
                  // 加载 XML 资源, 解析并且生成 BeanDefinition
                  xmlBeanDefinitionReader.loadBeanDefinitions(xmlSourcePath);
          
                  // 依赖查找 并且 创建 Bean  (注意: 依赖查找的过程中会伴随着创建Bean)
                  UserHolder userHolder = beanFactory.getBean(UserHolder.class);
                  System.out.println(userHolder);
              }
          
          }
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          
      • .Java 注解配置元信息

        • AnnotationDependencySetterInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.annotation.Qualifier;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          import org.springframework.context.annotation.Bean;
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          /**
           * 基于 注解 资源的依赖 Setter 方法注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AnnotationDependencySetterInjectionDemo {
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 注册 Configuration Class 配置类
                  applicationContext.register(AnnotationDependencySetterInjectionDemo.class);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  UserHolder userHolder = applicationContext.getBean(UserHolder.class);
                  System.out.println(userHolder);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
              /**
               * 加@Qualifier是通过Bean名称, 没加是通过Bean类型去找User
               * @param user
               * @return
               */
              @Bean
              public UserHolder userHolder(@Qualifier("user") User user) {
                  UserHolder userHolder = new UserHolder();
                  userHolder.setUser(user);
                  return userHolder;
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          
      • API 配置元信息

        • ApiDependencySetterInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.annotation.Qualifier;
          import org.springframework.beans.factory.config.BeanDefinition;
          import org.springframework.beans.factory.support.BeanDefinitionBuilder;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          import org.springframework.context.annotation.Bean;
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          /**
           * 基于 API 资源的依赖 Setter 方法注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class ApiDependencySetterInjectionDemo {
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 生成 UserHolder 的 BeanDefinition
                  BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
          
                  // 注册 UserHolder 的 BeanDefinition
                  applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  UserHolder userHolder = applicationContext.getBean(UserHolder.class);
                  System.out.println(userHolder);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
              /**
               * 为 {@link UserHolder} 生成 {@link BeanDefinition}
               * @return
               */
              private static BeanDefinition createUserHolderBeanDefinition() {
                  BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
                  // 设置属性值
                  beanDefinitionBuilder.addPropertyReference("user", "user");
                  return beanDefinitionBuilder.getBeanDefinition();
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          
    • 自动模式

      • byName

        • autowiring-dependency-setter-injection.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          
              <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
          
              <!--    setter依赖注入  -->
              <bean class="org.xiaoge.thinking.in.spring.ioc.dependency.injection.UserHolder"
                    autowire="byName">
          
              </bean>
          
          </beans>
          
        • AutowiringByNameDependencySetterInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.support.DefaultListableBeanFactory;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          
          /**
           * "byName/byType" Autowiring 依赖 setter 注入示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AutowiringByNameDependencySetterInjectionDemo {
          
              public static void main(String[] args) {
                  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          
                  String xmlSourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
          
                  // 加载 XML 资源, 解析并且生成 BeanDefinition
                  xmlBeanDefinitionReader.loadBeanDefinitions(xmlSourcePath);
          
                  // 依赖查找 并且 创建 Bean  (注意: 依赖查找的过程中会伴随着创建Bean)
                  UserHolder userHolder = beanFactory.getBean(UserHolder.class);
                  System.out.println(userHolder);
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          
      • byType

        • autowiring-dependency-setter-injection.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          
              <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
          
              <!--    setter依赖注入  -->
              <bean class="org.xiaoge.thinking.in.spring.ioc.dependency.injection.UserHolder"
                    autowire="byType">
          
              </bean>
          
          </beans>
          
        • AutowiringByNameDependencySetterInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.support.DefaultListableBeanFactory;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          
          /**
           * "byName/byType" Autowiring 依赖 setter 注入示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AutowiringByNameDependencySetterInjectionDemo {
          
              public static void main(String[] args) {
                  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          
                  String xmlSourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
          
                  // 加载 XML 资源, 解析并且生成 BeanDefinition
                  xmlBeanDefinitionReader.loadBeanDefinitions(xmlSourcePath);
          
                  // 依赖查找 并且 创建 Bean  (注意: 依赖查找的过程中会伴随着创建Bean)
                  UserHolder userHolder = beanFactory.getBean(UserHolder.class);
                  System.out.println(userHolder);
              }
          
          }
          
          
          // 运行结果 
          UserHolder{user=SuperUser{address='武汉'} User{id=1, name='xiaoge'}}
          
          因为superUser加了primary="true"
          

6. 构造器依赖注入:官方为什么推荐使用构造器注入?

  • 实现方法

    • 手动模式

      • XML 资源配置元信

        • dependency-constructor-injection.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          
              <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
          
              <!--    setter依赖注入  -->
              <bean class="org.xiaoge.thinking.in.spring.ioc.dependency.injection.UserHolder">
                  <constructor-arg name="user" ref="superUser"></constructor-arg>
              </bean>
          
          </beans>
          
        • 1

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.support.DefaultListableBeanFactory;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          
          /**
           * 基于 XML 资源的依赖 Constructor 注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class XmlDependencyConstructorInjectionDemo {
          
              public static void main(String[] args) {
                  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          
                  String xmlSourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";
          
                  // 加载 XML 资源, 解析并且生成 BeanDefinition
                  xmlBeanDefinitionReader.loadBeanDefinitions(xmlSourcePath);
          
                  // 依赖查找 并且 创建 Bean  (注意: 依赖查找的过程中会伴随着创建Bean)
                  UserHolder userHolder = beanFactory.getBean(UserHolder.class);
                  System.out.println(userHolder);
              }
          
          }
          
          // 运行结果
          UserHolder{user=SuperUser{address='武汉'} User{id=1, name='xiaoge'}}
          
      • Java 注解配置元信息

        • AnnotationDependencyConstructorInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.annotation.Qualifier;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          import org.springframework.context.annotation.Bean;
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          /**
           * 基于 注解 资源的依赖 Constructor 注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AnnotationDependencyConstructorInjectionDemo {
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 注册 Configuration Class 配置类
                  applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  UserHolder userHolder = applicationContext.getBean(UserHolder.class);
                  System.out.println(userHolder);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
              /**
               * 加@Qualifier是通过Bean名称, 没加是通过Bean类型去找User
               * @param user
               * @return
               */
              @Bean
              public UserHolder userHolder(@Qualifier("user") User user) {
                  return new UserHolder(user);
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          
      • API 配置元信息

        • ApiDependencyConstructorInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.config.BeanDefinition;
          import org.springframework.beans.factory.support.BeanDefinitionBuilder;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          
          /**
           * 基于 API 资源的依赖 Constructor 注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class ApiDependencyConstructorInjectionDemo {
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 生成 UserHolder 的 BeanDefinition
                  BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
          
                  // 注册 UserHolder 的 BeanDefinition
                  applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  UserHolder userHolder = applicationContext.getBean(UserHolder.class);
                  System.out.println(userHolder);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
              /**
               * 为 {@link UserHolder} 生成 {@link BeanDefinition}
               * @return
               */
              private static BeanDefinition createUserHolderBeanDefinition() {
                  BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
                  // 构造器设置属性值, 这个只有一个参数, 构造器如果有3个参数, 依次调三次这个方法addConstructorArgReference, 我这里只有一个所以写一次
                  beanDefinitionBuilder.addConstructorArgReference("superUser");
                  return beanDefinitionBuilder.getBeanDefinition();
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=SuperUser{address='武汉'} User{id=1, name='xiaoge'}}
          
    • 自动模式

      • constructor

        • autowiring-dependency-constructor-injection.xml

          <?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
                  https://www.springframework.org/schema/beans/spring-beans.xsd">
          
          
              <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
          
              <!--    setter依赖注入  -->
              <bean class="org.xiaoge.thinking.in.spring.ioc.dependency.injection.UserHolder"
                    autowire="constructor">
          
              </bean>
          
          </beans>
          
        • AutowiringConstructorDependencyConstructorInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.support.DefaultListableBeanFactory;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          
          /**
           * "constructor" Autowiring 依赖 Constructor 注入示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AutowiringConstructorDependencyConstructorInjectionDemo {
          
              public static void main(String[] args) {
                  DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          
                  String xmlSourcePath = "classpath:/META-INF/autowiring-dependency-constructor-injection.xml";
          
                  // 加载 XML 资源, 解析并且生成 BeanDefinition
                  xmlBeanDefinitionReader.loadBeanDefinitions(xmlSourcePath);
          
                  // 依赖查找 并且 创建 Bean  (注意: 依赖查找的过程中会伴随着创建Bean)
                  UserHolder userHolder = beanFactory.getBean(UserHolder.class);
                  System.out.println(userHolder);
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=SuperUser{address='武汉'} User{id=1, name='xiaoge'}}
          

7. 字段注入:为什么Spring官方文档没有单独列举这种注入方式?

  • 实现方法

    • 手动模式

      • Java 注解配置元信息

        • @Autowired

        • @Resource

        • @Inject(可选)

        • AnnotationDependencyFieldInjectionDemo.java

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.beans.factory.annotation.Qualifier;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          import org.springframework.context.annotation.Bean;
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          import javax.annotation.Resource;
          
          /**
           * 基于 注解 资源的依赖 Field 注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AnnotationDependencyFieldInjectionDemo {
          
              @Autowired
              private
                  // static  @Autowired 会忽略掉静态字段 所以加嘞static userHolder为null
                      UserHolder userHolder;
          
              @Resource  // @Resource 标注的字段同理 不能为static 为static就会报错
              private UserHolder userHolder2;
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 注册 Configuration Class 配置类
                  applicationContext.register(AnnotationDependencyFieldInjectionDemo.class);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  AnnotationDependencyFieldInjectionDemo demo = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);
                  System.out.println(demo.userHolder);
                  System.out.println(demo.userHolder2);
                  System.out.println(demo.userHolder == demo.userHolder2);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
              /**
               * 加@Qualifier是通过Bean名称, 没加是通过Bean类型去找User
               * @param user
               * @return
               */
              @Bean
              public UserHolder userHolder(@Qualifier("user") User user) {
                  return new UserHolder(user);
              }
          
          }
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          UserHolder{user=User{id=1, name='xiaoge'}}
          true
          

          所以这里指的字段注入, 是指的实例字段/对象字段

8. 方法注入:方法注入是@Autowired专利吗?

  • 实现方法

    • 手动模式

      • Java 注解配置元信息

        • @Autowired

        • @Resource

        • @Inject(可选)

        • @Bean

        • AnnotationDependencyMethodInjectionDemo

          package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
          
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.beans.factory.annotation.Qualifier;
          import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
          import org.springframework.context.annotation.AnnotationConfigApplicationContext;
          import org.springframework.context.annotation.Bean;
          import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
          
          import javax.annotation.Resource;
          
          /**
           * 基于 注解 资源的依赖 Method 注入 示例
           *
           * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
           * @since
           */
          public class AnnotationDependencyMethodInjectionDemo {
          
          
              private UserHolder userHolder;
          
              private UserHolder userHolder2;
          
              @Autowired
              public void initUserHolder(UserHolder userHolder) {
                  this.userHolder = userHolder;
              }
          
              @Resource
              public void initUserHolder2(UserHolder userHolder2) {
                  this.userHolder2 = userHolder2;
              }
          
              /**
               * 加@Qualifier是通过Bean名称, 没加是通过Bean类型去找User
               * @param user
               * @return
               */
              @Bean
              public UserHolder userHolder(@Qualifier("user") User user) {
                  return new UserHolder(user);
              }
          
          
              public static void main(String[] args) {
                  // 创建 ApplicationContext 容器
                  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          
                  // 注册 Configuration Class 配置类
                  applicationContext.register(AnnotationDependencyMethodInjectionDemo.class);
          
                  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
                  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
          
                  // 启动应用上下文
                  applicationContext.refresh();
          
                  AnnotationDependencyMethodInjectionDemo demo = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);
                  System.out.println(demo.userHolder);
                  System.out.println(demo.userHolder2);
                  System.out.println(demo.userHolder == demo.userHolder2);
          
                  // 关闭应用上下文
                  applicationContext.close();
              }
          
          
          
          }
          
          
          
          // 运行结果
          UserHolder{user=User{id=1, name='xiaoge'}}
          UserHolder{user=User{id=1, name='xiaoge'}}
          true
          

          注意: 方法注入只关注方法参数类型(不关注方法名称, 方法名称可以随便写), 它会去spring上下文中去找对应类型的对象赋值给方法的参数

9. 接口回调注入:回调注入的使用场景和限制有哪些?

  • Aware 系列接口回调

    • 自动模式

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LDRF49VT-1669797885494)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125152547024.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nysGzMrK-1669797885494)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125152604985.png)]

      AwareInterfaceDependencyInjectionDemo.java

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.Aware;
      import org.springframework.beans.factory.BeanFactory;
      import org.springframework.beans.factory.BeanFactoryAware;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.beans.factory.support.DefaultListableBeanFactory;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.ApplicationContextAware;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      
      /**
       * 基于 ${@link Aware} 接口回调的依赖注入 示例
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
      
          private static BeanFactory beanFactory;
      
          private static ApplicationContext  applicationContext;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类 -> springBean
              context.register(AwareInterfaceDependencyInjectionDemo.class);
      
              // 启动应用上下文
              context.refresh();
      
              /*
               因为 AnnotationConfigApplicationContext 本身没有能力去获取Bean
               它是通过context.getBeanFactory()获取DefaultListableBeanFactory对象去查询bean
               */
              System.out.println(AwareInterfaceDependencyInjectionDemo.beanFactory == context.getBeanFactory());
              System.out.println(applicationContext == context);
      
              // 关闭应用上下文
              context.close();
          }
      
          public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
              AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
          }
      
          public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
              AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
          }
      }
      
      
      // 运行结果
      true
      true
      

10. 依赖注入类型选择:各种依赖注入有什么样的使用场景?

  • 注入选型
    • 低依赖:构造器注入
      • 超过三个参数建议用Setter方式
    • 多依赖:Setter 方法注入
      • Setter注入也有一个弊端, setter注入, 它的先后顺序, 使我们开发者使用来觉得的, 这样就会产生一个问题, 字段依赖的时候, 我们必须要先注入谁, 在注入谁, 要思路清晰
    • 便利性:字段注入
    • 声明类:方法注入
      • 建议使用@Bean注解, 不推荐使用@Autowired/@Resource

11. 基础类型注入:String和Java原生类型也能注入Bean的属性,它们算依赖注入吗?

  • 基础类型

    • 原生类型(Primitive):boolean、byte、char、short、int、float、long、double

    • 标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、 Properties、UUID

    • 常规类型(General):Object、String、TimeZone、Calendar、Optional 等

    • Spring 类型:Resource、InputSource、Formatter 等

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FJ3Giot-1669797885495)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164309237.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b74KpryM-1669797885495)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164429336.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WAFGUlCe-1669797885495)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164444863.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZjjZPcCU-1669797885496)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164517057.png)]

      resource为什么打印出来会有class path resource因为它是掉的ClassPathResource的toString方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0BFgnvq-1669797885496)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164713707.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRkNSeuA-1669797885496)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164724118.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DMWWKScN-1669797885496)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221125164750366.png)]

12. 集合类型注入:注入Collection和Map类型的依赖区别?还支持哪些集合类型?

  • 集合类型

    • 数组类型(Array):原生类型、标量类型、常规类型、Spring 类

    • 集合类型(Collection)

      • Collection:List、Set(SortedSet、NavigableSet、EnumSet)

      • Map:Properties

      • User.java

        package org.xiaoge.thinking.in.spring.ioc.overview.domain;
        
        import org.omg.CORBA.PRIVATE_MEMBER;
        import org.springframework.core.io.Resource;
        import org.xiaoge.thinking.in.spring.ioc.overview.Enum.City;
        
        import java.util.Arrays;
        import java.util.List;
        import java.util.Map;
        
        /**
         * @Classname User
         * @Date 2022/10/17 14:57
         * @Created by ZhangXiao
         * @Description TODO
         */
        public class User {
        
            private Long id;
        
            private String name;
        
            private City city;
        
            private Resource configFileLocation;
        
            private City[] workCities;
        
            private List<City> lifeCities;
        
            private Map<Object, Object> map;
        
            public Long getId() {
                return id;
            }
        
            public void setId(Long id) {
                this.id = id;
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public City getCity() {
                return city;
            }
        
            public void setCity(City city) {
                this.city = city;
            }
        
            public Resource getConfigFileLocation() {
                return configFileLocation;
            }
        
            public void setConfigFileLocation(Resource configFileLocation) {
                this.configFileLocation = configFileLocation;
            }
        
            public City[] getWorkCities() {
                return workCities;
            }
        
            public void setWorkCities(City[] workCities) {
                this.workCities = workCities;
            }
        
            public List<City> getLifeCities() {
                return lifeCities;
            }
        
            public void setLifeCities(List<City> lifeCities) {
                this.lifeCities = lifeCities;
            }
        
            public Map<Object, Object> getMap() {
                return map;
            }
        
            public void setMap(Map<Object, Object> map) {
                this.map = map;
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "id=" + id +
                        ", name='" + name + '\'' +
                        ", city=" + city +
                        ", configFileLocation=" + configFileLocation +
                        ", workCities=" + Arrays.toString(workCities) +
                        ", lifeCities=" + lifeCities +
                        ", map=" + map +
                        '}';
            }
        
            public static User createUser() {
                User user = new User();
                user.setId(1L);
                user.setName("xiaoge");
                return user;
            }
        }
        
        
      • dependency-lookup-context.xml

        <?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
                https://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <!--    实施加载bean-->
            <bean id="user" class="org.xiaoge.thinking.in.spring.ioc.overview.domain.User">
                <property name="id" value="1" />
                <property name="name" value="xiaoge"/>
                <property name="city" value="WUHAN"/>
                <property name="configFileLocation" value="classpath:/META-INF/dependency-lookup-context.xml"/>
                <property name="workCities" value="WUHAN, HANGZHOU"/>
        <!--        <property name="lifeCities" value="WUHAN, BEIJING"/>-->
                <property name="lifeCities">
                    <list>
                        <value>WUHAN</value>
                        <value>BEIJING</value>
                    </list>
                </property>
                <property name="map">
                    <map>
                       <entry key="one" value="1" />
                       <entry key="two" value="2" />
                    </map>
                </property>
            </bean>
        
            <!-- 延迟bean 是沟通objectFactory简介创建的 -->
            <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
                <property name="targetBeanName" value="user" />
            </bean>
        
            <!-- parent继承 -->
            <bean id="superUser" class="org.xiaoge.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user" primary="true">
                <property name="address" value="武汉" />
            </bean>
        
        </beans>
        
      • DependencyLookupDemo.java

        package org.xiaoge.thinking.in.spring.ioc.overview.dependency.lookup;
        
        import org.springframework.beans.factory.BeanFactory;
        import org.springframework.beans.factory.ListableBeanFactory;
        import org.springframework.beans.factory.ObjectFactory;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        import org.xiaoge.thinking.in.spring.ioc.overview.annotation.Super;
        import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
        
        import java.util.Map;
        
        /**
         * 依赖查找示例
         *     1. 通过名称的方式查找
         *          1. 实时查找 lookupInRealTime
         *          2. 延迟查找 lookupInLazy
         *     2. 根据类型查找
         *          1. 根据类型查找单个bean lookupByType
         *          2. 根据类型查找集合对象Map<beanid, bean集合> lookupCollectionByType
         *     3. 根据java注解查找
         *          1. 单个bean对象/集合bean对象 lookupAnnotationByType
         *
         * @Classname DependencyLookupDemo
         * @Date 2022/10/17 14:56
         * @Created by ZhangXiao
         * @Description TODO
         */
        public class DependencyLookupDemo {
        
            public static void main(String[] args) {
                // 配置xml配置文件
                // 启动spring应用上下文
                BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-lookup-context.xml");
        
                lookupInRealTime(beanFactory);
                lookupInLazy(beanFactory);
        
                lookupByType(beanFactory);
                lookupCollectionByType(beanFactory);
        
                lookupAnnotationByType(beanFactory);
            }
        
        
            /**
             * 根据注解查找集合对象
             * @param beanFactory
             */
            private static void lookupAnnotationByType(BeanFactory beanFactory) {
                if (beanFactory instanceof ListableBeanFactory) {
                    ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
                    Map<String, User> map = (Map)listableBeanFactory.getBeansWithAnnotation(Super.class);
                    System.out.println("查找所有标注: @Super 所有的 user 集合对象: " + map);
                }
            }
        
        
            /**
             * 根据类型查找集合对象
             * @param beanFactory
             */
            private static void lookupCollectionByType(BeanFactory beanFactory) {
                if (beanFactory instanceof ListableBeanFactory) {
                    ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
                    Map<String, User> map = listableBeanFactory.getBeansOfType(User.class);
                    System.out.println("查找到所有的 user 集合对象: " + map);
                }
            }
        
        
            /**
             * 根据类型实时查找
             * @param beanFactory
             */
            private static void lookupByType(BeanFactory beanFactory) {
                User user = beanFactory.getBean(User.class);
                System.out.println("实时查找: " + user);
            }
        
        
            /**
             * 延迟加载bean
             * @param beanFactory
             */
            public static void lookupInLazy(BeanFactory beanFactory) {
                ObjectFactory<User> objectFactory = (ObjectFactory<User>)beanFactory.getBean("objectFactory");
                User user = objectFactory.getObject();
                System.out.println("延迟查找: " + user);
            }
        
            /**
             * 实施加载bean
             * @param beanFactory
             */
            public static void lookupInRealTime(BeanFactory beanFactory) {
                User user = (User)beanFactory.getBean("user");
                System.out.println("实时查找: " + user);
            }
        }
        
        
        // 运行结果
        实时查找: User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
        延迟查找: User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
        实时查找: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
        查找到所有的 user 集合对象: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
        查找所有标注: @Super 所有的 user 集合对象: {superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
        
        

13. 限定注入:如何限定Bean名称注入?如何实现Bean逻辑分组注入?

  • 使用注解 @Qualifier 限定

    • 通过 Bean 名称限定

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      /**
       * {@link Qualifier} 注解依赖注入
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @see Qualifier
       * @since
       */
      public class QualifierAnnotationDependencylrjectionDemo {
      
          @Autowired
          private User user;  // super user -> primary = true
      
          @Autowired
          @Qualifier("user")
          private User namedUser; // 指定 Bean 名称 或 ID
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(QualifierAnnotationDependencylrjectionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              QualifierAnnotationDependencylrjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencylrjectionDemo.class);
      
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.namedUser: " + demo.namedUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.namedUser: User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      
    • 通过分组限定

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      
      /**
       * {@link Qualifier} 注解依赖注入
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @see Qualifier
       * @since
       */
      public class QualifierAnnotationDependencylrjectionDemo {
      
          @Autowired
          private User user;  // super user -> primary = true
      
          @Autowired
          @Qualifier("user")
          private User namedUser; // 指定 Bean 名称 或 ID
      
          @Autowired // 只会获取不带Qualifier的Bean
          private Collection<User> allUsers; // 2 Bean -> super user, user
      
          @Autowired
          @Qualifier // 只会获取带Qualifier的Bean
          private Collection<User> qualifierUsers; // 2 Bean -> user1, user2
      
          @Bean
          @Qualifier // 进行逻辑分组
          public User user1() {
              User user = new User();
              user.setId(7L);
              return user;
          }
      
          @Bean
          @Qualifier // 进行逻辑分组
          public User user2() {
              User user = new User();
              user.setId(8L);
              return user;
          }
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(QualifierAnnotationDependencylrjectionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              QualifierAnnotationDependencylrjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencylrjectionDemo.class);
      
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.namedUser: " + demo.namedUser);
      
              System.out.println("demo.allUsers: " + demo.allUsers);
              System.out.println("demo.qualifierUsers: " + demo.qualifierUsers);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.namedUser: User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.allUsers: [User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}]
      demo.qualifierUsers: [User{id=7, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}, User{id=8, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}]
      

      自定义分组注解, UserGroup

      UserGroup

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.annotation.Qualifier;
      
      import java.lang.annotation.*;
      
      /**
       * 用户组注解: 扩展 {@link Qualifier  @Qualifier}
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Inherited
      @Documented
      @Qualifier
      public @interface UserGroup {
      }
      

      QualifierAnnotationDependencylrjectionDemo

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import javax.jws.soap.SOAPBinding;
      import java.util.Collection;
      
      /**
       * {@link Qualifier} 注解依赖注入
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @see Qualifier
       * @since
       */
      public class QualifierAnnotationDependencylrjectionDemo {
      
          @Autowired
          private User user;  // super user -> primary = true
      
          @Autowired
          @Qualifier("user")
          private User namedUser; // 指定 Bean 名称 或 ID
      
          @Autowired // 只会获取不带Qualifier的Bean
          private Collection<User> allUsers; // 2 Bean -> super user, user
      
          @Autowired
          @Qualifier // 只会获取带Qualifier的Bean
          private Collection<User> qualifierUsers; // 2 Bean -> user1, user2, user3, user4
      
          @Autowired
          @UserGroup
          private Collection<User> userGroupUsers; // 2 Bean -> user3, user4
      
          @Bean
          @Qualifier // 进行逻辑分组
          public User user1() {
              return createUser(7L);
          }
      
          @Bean
          @Qualifier // 进行逻辑分组
          public User user2() {
              return createUser(8L);
          }
      
          @Bean
          @UserGroup // 进行逻辑分组
          public User user3() {
              return createUser(9L);
          }
      
          @Bean
          @UserGroup // 进行逻辑分组
          public User user4() {
              return createUser(10L);
          }
      
          public static User createUser(Long id) {
              User user = new User();
              user.setId(id);
              return user;
          }
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(QualifierAnnotationDependencylrjectionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              QualifierAnnotationDependencylrjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencylrjectionDemo.class);
      
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.namedUser: " + demo.namedUser);
      
              System.out.println("demo.allUsers: " + demo.allUsers);
              System.out.println("demo.qualifierUsers: " + demo.qualifierUsers);
              System.out.println("demo.userGroupUsers: " + demo.userGroupUsers);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.namedUser: User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.allUsers: [User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}]
      demo.qualifierUsers: [User{id=7, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}, User{id=8, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}, User{id=9, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}, User{id=10, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}]
      demo.userGroupUsers: [User{id=9, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}, User{id=10, name='null', city=null, configFileLocation=null, workCities=null, lifeCities=null, map=null}]
      
  • 基于注解 @Qualifier 扩展限定

    • 自定义注解 - 如 Spring Cloud @LoadBalanced

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LKpYCUuC-1669797885497)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128105248225.png)]

14. 延迟依赖注入:如何实现延迟执行依赖注入?与延迟依赖查找是类似的吗?

  • 使用 API ObjectFactory 延迟注入

    • 单一类型
    • 集合类型
  • 使用 API ObjectProvider 延迟注入(推荐)

    • 单一类型
    • 集合类型
  • LazyAnnotationDependencyInjectionDemo

    package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
    
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    import javax.jws.soap.SOAPBinding;
    import java.util.Collection;
    
    /**
     * {@link ObjectProvider} 实现延迟依赖注入
     *
     * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
     * @since
     */
    public class LazyAnnotationDependencyInjectionDemo {
    
        @Autowired
        private User user; // 实时注入
    
        @Autowired
        private ObjectProvider<User> userObjectProvider; // 延迟注入
    
        @Autowired
        private ObjectFactory<Collection<User>> userObjectFactoryCollection; // 延迟注入
    
        public static void main(String[] args) {
            // 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 注册 Configuration Class 配置类
            applicationContext.register(LazyAnnotationDependencyInjectionDemo.class);
    
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
            xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
    
            // 启动应用上下文
            applicationContext.refresh();
    
            LazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);
    
            // 输出 super user --> primary = true
            System.out.println("demo.user: " + demo.user);
            // 输出 super user
            System.out.println("demo.userObjectProvider: " + demo.userObjectProvider.getObject()); // ObjectProvider 继承 ObjectFactory
            // 输出 user, super user
            System.out.println("demo.userObjectFactory: " + demo.userObjectFactoryCollection.getObject());
    
            // 输出 user, super user
            demo.userObjectProvider.forEach(System.out::println);
    
            // 关闭应用上下文
            applicationContext.close();
        }
    
    }
    
    
    // 运行结果
    demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.userObjectProvider: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.userObjectFactory: [User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}]
    User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    

15. 依赖处理过程:依赖处理时会发生什么?其中与依赖查找的差异在哪?

  • 基础知识

    • 入口 - DefaultListableBeanFactory#resolveDependency

      AnnotationDependencyInjectionResolutionDemo 注入单个Bean

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4mZOIAOf-1669797885497)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128133614932.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8hs0i9PS-1669797885497)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128134151416.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wiZlFf97-1669797885498)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128134342366.png)]

      C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128134701951.png

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qwQVWBVM-1669797885498)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128134932540.png)]

      因为我们xml定义了user和super user 所以这里有两个名称

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sQKW717F-1669797885498)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135019022.png)]

      它会加入两次

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IIm1dULL-1669797885499)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135313430.png)]

      找到了两个

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-71MGIJb2-1669797885499)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135348382.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6aZ6g0Z-1669797885499)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135551329.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1cyUIsNC-1669797885499)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135625674.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bzaDjvo-1669797885500)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135734720.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KohpNKJR-1669797885500)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135822799.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZBjGh1U-1669797885500)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135837587.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tclg0mfR-1669797885500)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128135859058.png)]

      所以说判断是否为primary其实就是用的BeanDefinition里面的元信息

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDE2Oqj3-1669797885501)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140105954.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cGVUV91-1669797885501)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140147105.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R7cwj2Eg-1669797885501)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140344771.png)]

      注意: 这里拿到的super user是个class

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2qdX1yY-1669797885501)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140532497.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m2dOCa7w-1669797885502)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140548684.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6qdt5cM-1669797885502)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128140612168.png)]

      AnnotationDependencyInjectionResolutionDemo 注入集合Bean

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Lazy;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      import java.util.Map;
      import java.util.Optional;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
          @Autowired
          private Map<String, User> mapUser;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.mapUser: " + demo.mapUser);
              System.out.println("demo.optionalUser: " + demo.optionalUser.get());
              System.out.println("demo.lazyUser: " + demo.lazyUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.mapUser: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
      demo.optionalUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Lazy;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      import java.util.Map;
      import java.util.Optional;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
          @Autowired
          private Map<String, User> mapUser;
      
          @Autowired
          private Optional<User> optionalUser;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.mapUser: " + demo.mapUser);
              System.out.println("demo.optionalUser: " + demo.optionalUser.get());
              System.out.println("demo.lazyUser: " + demo.lazyUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.mapUser: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
      

      其他同上唯一的就是这里事处理过个Bean

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5pUqs8iG-1669797885502)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128144850630.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vy8UMM08-1669797885502)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128144725412.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hkz0RSi-1669797885503)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128145011091.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jzNB9NCn-1669797885503)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128145125719.png)]

      AnnotationDependencyInjectionResolutionDemo 注入Optional Bean

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Lazy;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      import java.util.Map;
      import java.util.Optional;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
          @Autowired
          private Map<String, User> mapUser;
      
          @Autowired
          private Optional<User> optionalUser;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.mapUser: " + demo.mapUser);
              System.out.println("demo.optionalUser: " + demo.optionalUser.get());
              System.out.println("demo.lazyUser: " + demo.lazyUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.mapUser: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
      demo.optionalUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EA60GzN0-1669797885503)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128170730478.png)]

      AnnotationDependencyInjectionResolutionDemo 注入延迟 Bean

      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Lazy;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import java.util.Collection;
      import java.util.Map;
      import java.util.Optional;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
          @Autowired
          private Map<String, User> mapUser;
      
          @Autowired
          private Optional<User> optionalUser;
      
          @Autowired
          @Lazy // 延迟Bean
          private User lazyUser;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.mapUser: " + demo.mapUser);
              System.out.println("demo.optionalUser: " + demo.optionalUser.get());
              System.out.println("demo.lazyUser: " + demo.lazyUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.mapUser: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
      demo.optionalUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.lazyUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3WXIlRq-1669797885503)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128170913324.png)]

    • 依赖描述符 - DependencyDescriptor

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iQScfAZJ-1669797885503)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128114505496.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Coe4DPru-1669797885504)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128131218321.png)]

      declaringClass: 当前声明注入, 注入描述, 换而言之它是一个被注入的容器, 那么这个容器就称为声明的这个类

      methodName: 方法名称可以为空, (方法注入)

      parameterTypes: 方法参数, 构造器参数来操作(构造器注入)

      parameterIndex: 参数索引它的顺序从0开始

      fieldName: 字段名(字段注入)

      required: 可以理解为Autowired注解里面的required

      eager: 可以理解为Lazy注解里面的value

      nestingLevel: 嵌套层次这里主要指的事@Autowired也有可能放在你的嵌套类里面去

      containingClass: 包含类

      resolvableType: 泛型类型

      typeDescriptor: 类型描述

      方法注入, 字段注入, 构造器注入, 是可选的如果三个都是空它就没没有注入的来源, 那这个显然是不对的

    • 自定绑定候选对象处理器 - AutowireCandidateResolver

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHO9QNyF-1669797885504)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128114354781.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvfGMXsr-1669797885504)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221128114424300.png)]

      多个Bean是用的Set去重的方式, 所以是没有顺序可言的

      总结

      1DefaultListableBeanFactory#resolveDependency  判断是否懒加载,懒加载直接返回CGLIB代理对象;
      2、doResolveDependency		开始进行依赖注入;
      3、resolveMultipleBeans			判断注入的对象是否是集合类型(Stream,Collection,Array,Map) ,是的话直接return4、findAutowireCandidates		根据类型查找所有匹配到的bean,返回一个Map对象;
      5、determineAutowireCandidate	选取唯一bean名称,如果有多个bean,即返回@Primary修饰的;
      6、通过BeanFactory#getBean返回结果
      

16. @Autowired注入:@Autowired注入的规则和原理有哪些?

  • @Autowired 注入规则

    • 非静态字段
    • 非静态方法
    • 构造器
  • @Autowired 注入过程

    • 元信息解析
    • 依赖查找
    • 依赖注入(字段、方法)
    package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
    
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    import java.util.Collection;
    import java.util.Map;
    import java.util.Optional;
    
    /**
     * 注解驱动的依赖注入处理过程
     *
     * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
     * @since
     */
    @Configuration
    public class AnnotationDependencyInjectionResolutionDemo {
    
        @Autowired // 依赖查找 (处理)
        private User user;  // DependencyDescriptor ->
                            // 必须 (required = true)
                            // 实时注入 (eager = true)
                            // 通过类型 (User.class)
                            // 字段名称 ("user")
                            // 是否首要 (primary = true)
    
    //    @Autowired
    //    private Map<String, User> mapUser;
    //
    //    @Autowired
    //    private Optional<User> optionalUser;
    //
    //    @Autowired
    //    @Lazy // 延迟Bean
    //    private User lazyUser;
    
        public static void main(String[] args) {
            // 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 注册 Configuration Class 配置类
            applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
    
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
            xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
    
            // 启动应用上下文
            applicationContext.refresh();
    
            AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
    
            // 输出 super user --> primary = true
            System.out.println("demo.user: " + demo.user);
    //        System.out.println("demo.mapUser: " + demo.mapUser);
    //        System.out.println("demo.optionalUser: " + demo.optionalUser.get());
    //        System.out.println("demo.lazyUser: " + demo.lazyUser);
    
            // 关闭应用上下文
            applicationContext.close();
        }
    
    }
    

    在这里插入图片描述

    在这里插入图片描述

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-znJCsFwt-1669799159681)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129185624440.png)]

    注意: 有CommonAnnotationBeanPostProcessor它会先执行CommonAnnotationBeanPostProcessor, 后执行AutowiredAnnotationBeanPostProcessor, 通过这个applyMergedBeanDefinitionPostProcessors方法循环就能看出, 想调整顺序自己修改order值

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Ks6ziOI-1669799159681)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129185731130.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFxReRvB-1669799159681)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190005684.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PfBWvejD-1669799159681)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129182716395.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ta4CknCa-1669799159681)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190223321.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oTIGO91M-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190245185.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jr4LdIMi-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129191855129.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aFxmThYw-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190540160.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AOA7UEsZ-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190933041.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s41cAu7d-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129190952366.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEInoP4m-1669799159682)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129191149729.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o8goofIN-1669799159683)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129191303375.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPbX9eN7-1669799159683)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129164438070.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sPXo8mHg-1669799159683)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221129191410051.png)]

    剩下跟15一样过程了

    总结:

    先是找元信息然后进行注入:主要流程:AbstractAutowireCapableBeanFactory#createBean()-->doCreateBean()
    1.调用applyMergedBeanDefinitionPostProcessors -> postProcessMergedBeanDefinition -> findAutowiringMetadata中找到该类中注解为AutowiredValueInject的字段、方法等
    2.调用populateBean -> postProcessProperties,先调用findAutowiringMetadata找到待注入的元信息(比如user),然后调用metadata的inject方法,底层调用的是AutowiredFieldElementAutowiredMethodElement的inject方法,
    2.1 构造DependencyDescriptor(比如user)
    2.2 调用beanFactory.resolveDependency获取待注入的bean(比如user),这里又是一轮的createBean(比如superUser不存在,则会创建)
    2.3 获取后进行反射注入:field.set(bean, value)
    

15-16连体总结:

AbstractApplicationContext#refresh#finishBeanFactoryInitialization 方法中,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)

通过 DefaultListableBeanFactory#preInstantiateSingletons 方法进行初始化,会通过 AbstractBeanFactory#getBean(beanName) 方法对每个 Bean 进行初始化

Bean 初始化的过程比较繁琐,大致过程如下:

1. 先找到对应的 BeanDefinition 对象,然后会走到 AbstractAutowireCapableBeanFactory#createBean 方法,**进行实例化****填充属性值**、调用 Bean**初始化方法**

2. 在填充属性值的过程,默认根据类型进行注入,那么在 AbstractAutowireCapableBeanFactory#autowireByType 的方法中会调用 DefaultListableBeanFactory#resolveDependency 方法进行注入,最后还是会通过 AbstractBeanFactory#getBean(beanName) 方法获取到需要注入的 Bean 对象
3. 在填充属性值的时候也会通过 AutowiredAnnotationBeanPostProcessor 注入属性值,该注入增强器会对 @Autowired 或者 @Value 注解标注的属性进行注入,也是通过 DefaultListableBeanFactory#resolveDependency 方法进行注入。具体过程可看 AutowiredAnnotationBeanPostProcessor 的私有内部类 AutowiredFieldElement#inject 方法

17. JSR-330 @Inject注入:@Inject与@Autowired的注入原理有怎样的联系?

  • @Inject 注入过程

    • 如果 JSR-330 存在于 ClassPath 中,复用 AutowiredAnnotationBeanPostProcessor 实现

      <!-- JSR 330 API -->
      <dependency>
          <groupId>javax.inject</groupId>
          <artifactId>javax.inject</artifactId>
          <version>1</version>
      </dependency>
      
      package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
      
      import org.springframework.beans.factory.ObjectFactory;
      import org.springframework.beans.factory.ObjectProvider;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Lazy;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      import javax.inject.Inject;
      import java.util.Collection;
      import java.util.Map;
      import java.util.Optional;
      
      /**
       * 注解驱动的依赖注入处理过程
       *
       * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
       * @since
       */
      @Configuration
      public class AnnotationDependencyInjectionResolutionDemo {
      
          @Autowired // 依赖查找 (处理)
          private User user;  // DependencyDescriptor ->
                              // 必须 (required = true)
                              // 实时注入 (eager = true)
                              // 通过类型 (User.class)
                              // 字段名称 ("user")
                              // 是否首要 (primary = true)
      
      //    @Autowired
      //    private Map<String, User> mapUser;
      //
      //    @Autowired
      //    private Optional<User> optionalUser;
      //
      //    @Autowired
      //    @Lazy // 延迟Bean
      //    private User lazyUser;
      
          @Inject
          private User injectUser;
      
          public static void main(String[] args) {
              // 创建 ApplicationContext 容器
              AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      
              // 注册 Configuration Class 配置类
              applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
      
              XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
              xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
      
              // 启动应用上下文
              applicationContext.refresh();
      
              AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
      
              // 输出 super user --> primary = true
              System.out.println("demo.user: " + demo.user);
              System.out.println("demo.injectUser: " + demo.injectUser);
      //        System.out.println("demo.mapUser: " + demo.mapUser);
      //        System.out.println("demo.optionalUser: " + demo.optionalUser.get());
      //        System.out.println("demo.lazyUser: " + demo.lazyUser);
      
              // 关闭应用上下文
              applicationContext.close();
          }
      
      }
      
      
      // 运行结果
      demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      demo.injectUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
      
    • 实现原理跟15-16一样

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VV9s27u2-1669797885505)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130112913241.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ujjWTy8q-1669797885505)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130112949260.png)]

      遍历来查询装饰的注解, 注意它是有顺序的集合, 所以会根据添加的注解顺序来进行操作

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h5MlcLxc-1669797885505)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130113024410.png)]

18. Java通用注解注入原理:Spring是如何实现@Resource和@EJB等注解注入的?

  • CommonAnnotationBeanPostProcessor

    • 注入注解
      • javax.xml.ws.WebServiceRef
      • javax.ejb.EJB
      • javax.annotation.Resource
    • 生命周期注解
      • javax.annotation.PostConstruct
      • javax.annotation.PreDestroy

    其实CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor差不多, 只不过CommonAnnotationBeanPostProcessor多了一个生命周期, CommonAnnotationBeanPostProcessor倒数第4位, AutowiredAnnotationBeanPostProcessor倒数第三位, 所以CommonAnnotationBeanPostProcessor先执行后执行AutowiredAnnotationBeanPostProcessor

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eu02lqVb-1669797885505)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130133215467.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AjZKwu6G-1669797885505)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130133232480.png)]

    CommonAnnotationBeanPostProcessor倒数第4位, AutowiredAnnotationBeanPostProcessor倒数第三位, 所以CommonAnnotationBeanPostProcessor先执行后执行AutowiredAnnotationBeanPostProcessor

    可以自定义order或者@Order

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mADi8Xi1-1669797885506)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130133813927.png)]

    它多个用的LifecycleMetadata元信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2dpHOPxg-1669797885506)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130143609594.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yeMKQhlC-1669797885506)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130143629469.png)]

    多了个初始化方法和销毁方法, 对应的就是PostConstruct/PreDestroy

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cz6737Wf-1669797885506)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130143646227.png)]

    找元信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9UtPGVAL-1669797885506)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130144304810.png)]

    跟AutowiredAnnotationBeanPostProcessor那个查询一样, 主要看buildResourceMetadata

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A1YREu1K-1669797885507)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130144604421.png)]

    @Resource也是不能放在含static的字段/方法的, 递归去查找元信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0py2VeOP-1669797885507)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130144625910.png)]

    PostConstruct/PreDestroy在哪里执行的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmFGDX7A-1669797885507)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130145125313.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bB8O5V1v-1669797885507)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130145155269.png)]

    它会去构建LifecycleElement的method方法, 所以生命周期的两个注解PostConstruct/PreDestroy只允许注入到方法上面

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZLsCCzhn-1669797885507)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130145433854.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9NQ9zCvZ-1669797885508)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130145518648.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yZ0xgHOq-1669797885508)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151347314.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEqUBUev-1669797885508)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151408515.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmxhvDNm-1669797885508)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151501110.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9sUAdBeX-1669797885508)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151522385.png)]

    递归先父类,后子类的PostConstruct/PreDestroy

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7r0RgHG-1669797885509)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151539975.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jTRbC8v-1669797885509)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151602824.png)]

    生命周期回调方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Vxw5eam-1669797885509)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221130151947979.png)]

19. 自定义依赖注入注解:如何最简化实现自定义依赖注入注解?

  • 基于 AutowiredAnnotationBeanPostProcessor 实现

    package org.xiaoge.thinking.in.spring.ioc.dependency.injection.annotation;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.lang.annotation.*;
    
    /**
     * 自定义注入使用(@Autowired 元注解)
     *
     * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
     * @since
     */
    @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Autowired
    public @interface MyAutowired {
    
        /**
         * Declares whether the annotated dependency is required.
         * <p>Defaults to {@code true}.
         */
        boolean required() default true;
    
    }
    
    
    package org.xiaoge.thinking.in.spring.ioc.dependency.injection.annotation;
    
    import java.lang.annotation.*;
    
    /**
     * 自定义依赖注入注解
     *
     * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
     * @since
     */
    @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface InjectedUser {
    
    }
    
    package org.xiaoge.thinking.in.spring.ioc.dependency.injection;
    
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    import org.xiaoge.thinking.in.spring.ioc.dependency.injection.annotation.InjectedUser;
    import org.xiaoge.thinking.in.spring.ioc.dependency.injection.annotation.MyAutowired;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    import javax.inject.Inject;
    import java.util.Collection;
    import java.util.Map;
    import java.util.Optional;
    
    import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;
    
    /**
     * 注解驱动的依赖注入处理过程
     *
     * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
     * @since
     */
    public class AnnotationDependencyInjectionResolutionDemo {
    
        @Autowired // 依赖查找 (处理)
        private User user;  // DependencyDescriptor ->
                            // 必须 (required = true)
                            // 实时注入 (eager = true)
                            // 通过类型 (User.class)
                            // 字段名称 ("user")
                            // 是否首要 (primary = true)
    
        @Autowired
        private Map<String, User> mapUser;
    
        @Autowired
        private Optional<User> optionalUser;
    
        @Autowired
        @Lazy // 延迟Bean
        private User lazyUser;
    
        @Inject
        private User injectUser;
    
        @MyAutowired
        private User myAutowiredUser;
    
        @InjectedUser
        private User injectedUser;
    
        /**
         *
         * 核心是Bean名称是AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, 因为它只会注入一次
         * 只注入我自己的注解, 其他注解全部失效, 想之前的也生效用setAutowiredAnnotationTypes吧其他注解也加载进来
         * @return
         */
    //    @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
    //    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
    //        AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
    //        autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
    //        return autowiredAnnotationBeanPostProcessor;
    //    }
    
        /**
         * 兼容老的api, 新老都生效 让容器里面存在两个(AutowiredAnnotationBeanPostProcessor)
         * @return
         */
        @Bean
        public static AutowiredAnnotationBeanPostProcessor beanPostProcessor2() {
            AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
            autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
            return autowiredAnnotationBeanPostProcessor;
        }
    
    
        /**
         * 无效
         * @return
         */
    //    @Bean
    //    public AutowiredAnnotationBeanPostProcessor beanPostProcessor2() {
    //        AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
    //        autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
    //        return autowiredAnnotationBeanPostProcessor;
    //    }
    
    
        public static void main(String[] args) {
            // 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 注册 Configuration Class 配置类
            applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
    
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
            xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/dependency-lookup-context.xml");
    
            // 启动应用上下文
            applicationContext.refresh();
    
            AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
    
            // 输出 super user --> primary = true
            System.out.println("demo.user: " + demo.user);
            System.out.println("demo.injectUser: " + demo.injectUser);
            System.out.println("demo.mapUser: " + demo.mapUser);
            System.out.println("demo.optionalUser: " + demo.optionalUser);
            System.out.println("demo.lazyUser: " + demo.lazyUser);
            System.out.println("demo.myAutowiredUser: " + demo.myAutowiredUser);// AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME
            System.out.println("demo.injectedUser: " + demo.injectedUser);// AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME
    
            // 关闭应用上下文
            applicationContext.close();
        }
    
    }
    
    
    // 运行结果
    demo.user: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.injectUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.mapUser: {user=User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}, superUser=SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}}
    demo.optionalUser: Optional[SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}]
    demo.lazyUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.myAutowiredUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    demo.injectedUser: SuperUser{address='武汉'} User{id=1, name='xiaoge', city=WUHAN, configFileLocation=class path resource [META-INF/dependency-lookup-context.xml], workCities=[WUHAN, HANGZHOU], lifeCities=[WUHAN, BEIJING], map={one=1, two=2}}
    

    就是因为它所以只有自定义注解生效了, 原有注解失效, 因为它只会注入一次, 而加了static的优先

    image-20221130162553984

    总结:

    上下文refresh后,会调用registerBeanPostProcessors注册各beanPostProcessors。此时demo所在的类并没有初始化为bean。
    但是如果要拿到自定义的AutowiredAnnotationBeanPostProcessor,就必须拿到demo的bean后调用beanPostProcessor来拿到这个PostProcessor bean。这就必然导致整个demo配置类先实例化初始化,也就导致@InjectUser注入的bean还没有被AutowiredAnnotationBeanPostProcessor解析,就注入进来了,也就是null。如果加上static,那么就不需要先拿到demo的bean,可以直接调用类方法获取这个AutowiredAnnotationBeanPostProcessor。那么就会导致先拿到processor,后拿到demo的bean。这样demo在初始化的时候,就会正常解析自定义@InjectUser。所以对于同时存在bean的定义和bean的注入的配置类,顺序很容易弄错。
    
  • 自定义实现

    • 生命周期处理
      • InstantiationAwareBeanPostProcessor
      • MergedBeanDefinitionPostProcessor
    • 元数据
      • InjectedElement
      • InjectionMetadata

20. 面试题精选

  • 有多少种依赖注入的方式?
    • 构造器注入
    • Setter 注入
    • 字段注入
    • 方法注入
    • 接口回调注入
  • 你偏好构造器注入还是 Setter 注入?
    • 答:两种依赖注入的方式均可使用,如果是必须依赖的话,那么推荐使用构造器注入,Setter 注入用于可选依赖。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/50352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

拓扑排序算法

背景 拓扑排序是啥意思&#xff1f; 拓扑排序是指: 将有向无环图(DAG)展开为一维的执行序列。DAG顾名思义就是有方向的图&#xff0c;下面这张图就简单说明了啥是有向无环图。一般人可能用到这个算法的情况不多&#xff0c;但是刷leetcode的课程表问题肯定遇到过&#xff0c;其…

ShardingJdbcⅡ

序言 在前文的基础上继续梳理一下分片的相关信息.基于shardingsphere-sharding-api:jar:5.2.1的源码,感觉ShardingJdbc的版本变动频繁且比较大cuiyaonan2000163.com 切入口是如下的内容,吐槽下官网的API文档不太够能把事情说清楚: 分片算法 从上面的自定义分片的可选类型我们…

我有两个列表,现在需要找出两个列表中的不同元素,怎么做?

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤秦时明月汉时关&#xff0c;万里长征人未还。大家好&#xff0c;我是皮皮。一、前言前几天在帮助粉丝解决问题的时候&#xff0c;遇到一个简单的小需求&#…

[附源码]Python计算机毕业设计Django的物品交换平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

【Pandas数据处理100例】(八十五):Pandas将DataFrame数据转化成字典数据

前言 大家好,我是阿光。 本专栏整理了《Pandas数据分析处理》,内包含了各种常见的数据处理,以及Pandas内置函数的使用方法,帮助我们快速便捷的处理表格数据。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmPandas版本:1.3.5N…

git push出现git@github.com: Permission denied (publickey) 解决办法

故障现象 ➜ LKExtentionKit git:(master) ✗ git push --set-upstream origin master gitgithub.com: Permission denied (publickey). 错误&#xff1a;无法读取远程仓库。请确认您有正确的访问权限并且仓库存在。 解决办法 第1步,验证邮箱与GitHub注册时输入的是否一致 …

计算机网络(详解)

文章目录一&#xff0c;计算机网络⑴ 局域网&#xff08;LAN&#xff09;1) 环状拓扑结构2) 星型拓扑结构3) 总线拓扑结构⑵ 城域网&#xff08;MAN&#xff09;⑶ 广域网&#xff08;WAN&#xff09;二&#xff0c;互联网⑴ 互联网是一种计算机网络⑵ 互联网的工作模式⑶ 互联…

Leetcode 907.子数组的最小值之和(中等)

一、题目 1、题目描述 给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 由于答案可能很大&#xff0c;因此 返回答案模 10^9 7 。 示例1&#xff1a; 输入&#xff1a;arr [3,1,2,4] 输…

【Paper】2022_离散时间多智能体系统编队-包围控制研究_李博凡

离散时间多智能体系统编队-包围控制研究_李博凡 文章目录第四章 基于间歇控制的离散时间多智能体系统编队-包围控制4.1 引言4.2 基于状态反馈的离散时间间歇多智能体系统编队-包围控制4.2.1 模型描述4.2.2 稳定性分析4.3 基于观测器的离散时间间歇多智能体系统编队-包围控制4.3…

2022最全Hbuilder打包成苹果IOS-App的详解

本文相关主要记录一下使用Hbuilder打包成苹果IOS-App的详细步骤。 介绍一下个人开发者账号&#xff1a; 再说下什么是免费的苹果开发者账号&#xff0c;就是你没交688年费的就是免费账号&#xff0c;如果你想变成付费开发者账号&#xff0c;提交申请付费就行&#xff0c;账号都…

qt中Qtcpserver服务端_qt websocket

0.前言 本文主要讲解 Qt TCP 相关接口的基本应用&#xff0c;一些实践相关的后面会单独写。 TCP 协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP 通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输。 TCP 通过三次握手来…

Feign的使用

1、Feigin接口&#xff1a; ProductClientService import com.mengxuegu.springcloud.entities.Product; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.anno…

SIMetrix导入MOS管SPICE参数进行仿真的快速方法

问题的提出 在采用SIMetrix 8.3软件进行E类放大器的仿真过程中&#xff0c;用到了NEXPERIA公司的NMOS管器件PMH550UNE, 但在SIMetrix 8.3的库中没有该器件&#xff0c;因此需要导入第三方库文件. 通常的办法是从生产该器件的公司网站上下载器件库文件&#xff0c;导入到SIMet…

MKS上游和下游集成式压力控制器的技术分析及其替代解决方案

摘要&#xff1a;目前的MKS系列集成式压力控制器本质上是一种流量调节和测量装置&#xff0c;无法直接用来进行准确的压力控制&#xff0c;而且MKS压力控制器还存在测量精度不高、压力控制范围有限和对工作介质洁净度要求很高的不足。为此&#xff0c;为了弥补这些不足&#xf…

Java 并发编程之ConcurrentHashMap源码详解

Java 并发编程之ConcurrentHashMap原理详解 文章目录Java 并发编程之ConcurrentHashMap原理详解原理剖析源码剖析一、构造方法分析二、初始化三、put()实现分析四、扩容原理剖析 HashMap通常的实现方式是“数组链表”&#xff0c;这种方式被称为“拉链法”。 ConcurrentHashMa…

K_A08_001 基于 STM32等单片机驱动L298N模块按键控制直流电机启停正反转加减速

目录 一、资源说明 二、基本参数 1、参数 2、引脚说明 三、驱动说明 L298N模块驱动时序 对应程序: ENA ENB输出PWM 四、部分代码说明 接线说明 1、STC89C52RCL298N模块 2、STM32F103C8T6L298N模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七、项…

宇视雷视工勘指导(卡口电警篇)

雷视工勘指导&#xff08;卡口电警篇&#xff09; 卡口和电子警察具备车辆信息采集、违法驾驶行为检测等功能&#xff0c;是城市道路交通治理的利器。为了提升现场工勘效率并保障工勘的质量&#xff0c;本次为大家介绍一款宇视的前端工勘神器——《宇视智能交通工勘计算表》&a…

SpringMVC-全面详解(学习总结---从入门到深化)

目录 SpringMVC简介 MVC模型 SpringMVC SpringMVC入门案例 SpringMVC执行流程 SpringMVC的组件 组件的工作流程 SpringMVC参数获取_封装为简单数据类型 SpringMVC参数获取_封装为对象类型 封装单个对象 封装关联对象 SpringMVC参数获取_封装为集合类型 封装为Lis…

Qt报错总结

转载 Qt报错 widget.obj的问题 遇到这种情况可能是链接出错造成的&#xff0c;所以需要首选就是需要将生成的bulid文件进行删除&#xff0c;然后运行&#xff0c;基本可以了 补充知识&#xff1a; QtCreator中qmake、构建、运行、清理等区别与联系 qt执行流程&#xff1a;qma…

模式也能开盲盒,”盲返“模式带动电商平台共享经济

今年元月份&#xff0c;国务院也是提出消费返利、消费优惠、利润分享属于电商平台共享经济的促销模式&#xff0c;属于合法合规的新业态经济以及新零售重大变革的突破&#xff0c;全民参与共同富裕。 而最近市场上出了个很火的电商模式——消费盲返&#xff0c;是一个针对每个…