spring源码学习---Spring IoC 依赖注入

一、依赖注入Dependency injection

直接在容器启动时通过构造器,getter setter等形式注入依赖。

优点:性能高,侵入小

与依赖查询两者区别:区别在于依赖的对象是否为主动获取,是的话,就是依赖查找,否则就是依赖注入,由框架绑定完成。

依赖查找 VS 依赖注入

在这里插入图片描述

二、依赖注入的模式和类型

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

    • XML 资源配置元信息
    • Java 注解配置元信息
    • API 配置元信息 (一般对容器扩展使用)

自动模式-实现方提供依赖自动关联的方式,按照内建的注入规则

    • Autowiring(自动绑定)

•依赖注入类型

依赖注入类型  配置元数据举例
Setter 方法  <proeprty name="user" ref="userBean"/>
构造器   <constructor-arg name="user" ref="userBean" />
字段  @Autowired User user;
方法   @Autowired public void user(User user) { ... }
接口回调  class MyBean implements BeanFactoryAware { ... }

2.1、Autowiring(自动绑定)

    Autowiring in Spring. Autowiring feature of spring framework enables you to inject the object dependency implicitly. It internally uses setter or constructor injection. Autowiring can't be used to inject primitive and string values. It works with reference only.

example:
    只需要在需要自动装配的bean标签上设置autowire=true即可,spring会自动在容器中查找依赖,并使用setter方法为我们装配依赖,我们需要做的就是在xml中声明依赖,如果使用了annotation,那事情将会变得更简单

代码示例:

   首先是创建两个类 Person 和 PersonHolder:

@Data
public class Person {
    private Long id;

    private String name;

    private Integer age;

    public Person() {
    }

    public Person(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}
public class PersonHolder {
    
    private Person person;
    public PersonHolder(Person person) {
        this.person = person;
    }

    public PersonHolder() {
    }
}

xml配置:

 <bean id="person" class="com.dukun.study.injection.enetity.Person">
        <property name="id" value="1"/>
        <property name="name" value="坤仔"/>
        <property name="age" value="19"/>
    </bean>
    <!-- Autowiring 构造器自动注入-->
    <bean  id="personHolderConstructor" class="com.dukun.study.injection.enetity.PersonHolder"
           autowire="constructor">
    </bean>
    <!-- Autowiring setter自动注入 这里会注入person 这个id-->
    <bean  id="personHolderSetterByName" class="com.dukun.study.injection.enetity.PersonHolder"
           autowire="byName">

2.2、Setter 方法注入:

xml示例:

  <!--  setter手动注入-->
    <bean id="personHolder" class="com.dukun.study.injection.enetity.PersonHolder">
          <property name="person" ref="person" />
    </bean>

2.3、构造器注入

xml示例:


    <!-- 构造器手动注入-->
    <bean  id="personHolderConstructorTwo" class="com.dukun.study.injection.enetity.PersonHolder">
        <constructor-arg name="person" ref="person" />
    </bean>

构造器注入和Setter 方法注入的区别:

  构造器注入 是按照构造器参数顺序决定的,

  Setter 方法注入是无序的。由于 Java 反射 API 所返回的 public 方法熟顺序并非定义顺序,所以无法控制先后情况

 

2.4、字段注入

• 实现方法 
    • 手动模式 
        • Java 注解配置元信息 
            • @Autowired  根据类型注入 (@Autowired 会忽略掉静态字段 也就是会注入失败)
            • @Resource  根据名称注入
            • @Inject(可选)

示例:

   @Autowired
    private
//    static // @Autowired 会忽略掉静态字段
            UserHolder userHolder;

    @Resource
    private UserHolder userHolder2;

2.5 、方法注入

• 实现方法 
    • 手动模式 
        • Java 注解配置元信息 
            • @Autowired  
            • @Resource 
            • @Inject(可选)

示例:

    private UserHolder userHolder;

    private UserHolder userHolder2;

    @Autowired
    public void init1(UserHolder userHolder) {
        this.userHolder = userHolder;
    }

    @Resource
    public void init2(UserHolder userHolder2) {
        this.userHolder2 = userHolder2;
    }

方法注入和Setter注入有什么不同?

 Setter 注入是通过 Java Beans 来实现的,而方法注入则是直接通过 Java 反射来做的。当然底层都是 Java 反射~

2.6、接口回调注入(接触少重点看下)

接口回调注入是指 实现spring 提供的接口, 获得相应的ioc容器,在向容器中注入.

     Spring内置了用于不同目的的大量回调接口,很多场合都会使用到它们。使用这些回调接口往往能够达到事半功倍的效果。一旦目标受管Bean实现了回调接口,则当DI容器实例化受管Bean时,DI容器就会自动调用这些回调接口所定义的方法,进而将相关对象注入进来。最终,受管Bean便可使用它们了。

内建接口 内建接口
BeanFactoryAware 获取IoC 容器-BeanFactory
ApplicationContextAware 获取Spring 应用上下文-ApplicationContext 对象
EnvironmentAware 获取Environment 对象
ResourceLoaderAware 获取资源加载器对象-ResourceLoader
BeanClassLoaderAware 获取加载当前Bean Class 的ClassLoader 
BeanNameAware 获取当前Bean 的名称
MessageSourceAware 获取MessageSource 对象,用于Spring 国际化
ApplicationEventPublisherAware 获取ApplicationEventPublishAware 对象,用于Spring 事件
EmbeddedValueResolverAware 获取StringValueResolver 对象,用于占位符处理

1、BeanFactoryAware回调接口 获取IoC 容器-BeanFactory

public interface BeanFactoryAware extends Aware {

	void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

2. ApplicationContextAware回调接口

类似于BeanFactoryAware回调接口,ApplicationContextAware使得受管Bean能够感知到IoC容器的存在, 它定义的回调方法如下。注意,ApplicationContextAware仅仅适合于ApplicationContext容器。

public interface ApplicationContextAware extends Aware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

示例代码:

/**
 * 基于 {@link Aware} 接口回调的依赖注入示例
 * Created by dukun on 2020/7/3.
 */
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware ,ApplicationContextAware {

    private static BeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        context.register(AwareInterfaceDependencyInjectionDemo.class);
        // 启动 Spring 应用上下文
        context.refresh();
        System.out.println(beanFactory == context.getBeanFactory());
        System.out.println(applicationContext == context);
        // 显示地关闭 Spring 应用上下文
        context.close();
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.applicationContext= applicationContext;
    }
}

其实 beanFactory和applicationContext属性 和从容器中获得是相等的 所以打印输出都是 true

2.7 基于 API 实现依赖 注入

基于api的注入 要手动生成 类的 的 BeanDefinition 对象在注入到容器中

代码示例:

/**
 *基于 API 实现依赖 Constructor 注入示例
 * 基于 API 实现依赖 Setter 方法注入示例
 * Created by dukun on 2020/7/3.
 */
public class ApiDependencyInjectionDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 生成 UserHolder 的 BeanDefinition
        //基于 API 实现依赖  Constructor 方法注入示例
        BeanDefinition userHolderBeanDefinitionSetter = createUserHolderBeanDefinitionSetter();
        //基于 API 实现依赖  Constructor 方法注入示例
        BeanDefinition userHolderBeanDefinitionConstructor = createUserHolderBeanDefinitionConstructor();
        applicationContext.registerBeanDefinition("userHolder1",userHolderBeanDefinitionSetter);
        applicationContext.registerBeanDefinition("userHolder2",userHolderBeanDefinitionConstructor);
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并且生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找并且创建 Bean
        UserHolder userHolder1 = (UserHolder) applicationContext.getBean("userHolder1");
        UserHolder userHolder2 = (UserHolder) applicationContext.getBean("userHolder2");
        System.out.println(userHolder1);
        System.out.println(userHolder2);
        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }

    /**
     * 基于 API 实现依赖 Setter 方法注入示例
     * 使用BeanDefinitionBuilder 生成BeanDefinition
     * @return
     */
    private static BeanDefinition createUserHolderBeanDefinitionSetter() {
        BeanDefinitionBuilder beanDefinitionBuilde=BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        beanDefinitionBuilde.addPropertyReference("user","superUser");
        return beanDefinitionBuilde.getBeanDefinition();
    }

    /**
     * 基于 API 实现依赖  Constructor 方法注入示例
     * 使用BeanDefinitionBuilder 生成BeanDefinition
     * @return
     */
    private static BeanDefinition createUserHolderBeanDefinitionConstructor() {
        BeanDefinitionBuilder beanDefinitionBuilde=BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        beanDefinitionBuilde.addConstructorArgReference("user");
        return beanDefinitionBuilde.getBeanDefinition();
    }
}

三、限定注入 @Qualifier 

•使用注解@Qualifier 限定

   • 通过Bean 名称限定
    • 通过分组限定

• 基于注解@Qualifier 扩展限定
    • 自定义注解-如Spring Cloud @LoadBalanced

3.1、通过Bean 名称限定

  @Autowired
    @Qualifier("person") // 指定 Bean 名称或 ID
    private Person namedUser;

3.2、通过分组限定

/**
 * @link Qualifier} 注解依赖注入
 * Created by dukun on 2020/7/3.
 */
public class QualifierAnnotationDependencyInjectionDemo {

    @Autowired
    @Qualifier("person") // 指定 Bean 名称或 ID
    private Person namedUser;

    @Autowired
    private Collection<Person> allPerson; //全部的bean

    @Autowired
    @Qualifier("group1") //限定使用分组获取bean
    private List<Person> group1Beans;

    @Autowired
    @Qualifier("group2")
    private List<Person> group2Beans;


    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找 QualifierAnnotationDependencyInjectionDemo Bean
        QualifierAnnotationDependencyInjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);
        System.out.println("demo.namedUser:" + demo.namedUser);
        System.err.println("demo.allPerso:" + demo.allPerson);
        System.err.println(" demo.group1Beans:" + demo.group1Beans);
        System.err.println(" demo.group2Beans:" + demo.group2Beans);

        applicationContext.close();
    }

    @Bean
    public Person person() {
        return createCallerInfo("person",0l);
    }

    @Bean
    @Qualifier("group1") //分组为group1
    public Person person1() {
        return createCallerInfo("person1",1l);
    }
    @Bean
    @Qualifier("group1")
    public Person person2() {
        return createCallerInfo("person2",2l);
    }

    @Bean
    @Qualifier("group2") //分组为group2
    public Person person3() {
        return createCallerInfo("person3",3l);
    }
    @Bean
    @Qualifier("group2")
    public Person person4() {
        return createCallerInfo("person4",4l);
    }

    private static Person createCallerInfo(String name,Long id) {
        Person person = new Person();
        person.setAge(18);
        person.setName(name);
        person.setId(id);
        return  person;
    }
}

3.3 基于注解@Qualifier 扩展限定  

    自定义注解-如Spring Cloud @LoadBalanced

  如果需要扩展只需要在 自定义注解上加上 @Qualifier 就可以就行分组限定

如:@LoadBalanced 只有 标注这个就说明是 开启负载均衡

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

自己自定义分组 自定义注解:

/**
 * 用户组注解,扩展 {@link Qualifier @Qualifier}
 *
 * @author 
 * @since
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface PersonGroup {
}

使用:

  @Bean
    @PersonGroup //分组为group2
    public Person person3() {
        return createCallerInfo("person3",3l);
    }
    @Bean
    @PersonGroup
    public Person person4() {
        return createCallerInfo("person4",4l);
    }

调用:

    @Autowired
    @PersonGroup
    private List<Person> group2Beans;

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章