spring注解驱动第五节之Bean的依赖注入

5. Bean的依赖注入

如何将一个组件自动注入到另外一个组件中呢?

5.1 @Autowired

@Autowired可以可以标注在构造器,方法,参数,字段上,默认按照Bean的类型去IOC容器中去寻找组件,如果有且一个组件被找到则成功注入,如果有多个组件被找到,则再使用默认名称去获取Bean,Bean的默认名称为类首字母缩写。也可以配合@Qualifier注解明确指定注入哪个Bean,还可以在注册Bean的地方使用@Primary,在不指定@Qualifier的情况下,默认注入@Primary修饰的Bean。如果Bean不一定存在,可以使用属性required=false,则Bean不存在也不会抛出异常。本文不演示构造注入、setter方法注入

  • 编写一个用来注入到另外一个类中的Bean AutowiredBean.java并使用@Component注入到容器中
package com.ddf.spring.annotation.bean;

import org.springframework.stereotype.Component;

/**
 * @author DDf on 2018/8/6
 */
@Component
public class AutowiredBean {
    public AutowiredBean() {
        System.out.println("AutowiredBean创建完成。。。。。。。。。。。。");
    }
}
  • 修改AnnotationConfiguration.java,增加方法autowiredBean2(),再次注入AutowiredBean,并取名autowiredBean2区分
package com.ddf.spring.annotation.configuration;

import com.ddf.spring.annotation.bean.*;
import com.ddf.spring.annotation.entity.User;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;

/**
 * @author DDf on 2018/7/19
 * @Configuration 表明当前类是一个配置类
 * @ComponentScan 指定扫描的包路径,并且配置了excludeFilters来排除注解类型为@Controller的不纳入容器中,
 * 排除符合自定义ExcludeTypeFilter类中规则的类
 * @Import 导入组件,可以直接导入普通类,或者通过ImportSelector接口或者ImportBeanDefinitionRegistrar接口来自定义导入
 */
@Configuration
@ComponentScan(value = "com.ddf.spring.annotation", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = ExcludeTypeFilter.class)
})
@Import(value = {ImportBean.class, CustomImportSelector.class, CustomImportBeanDefinitionRegistrar.class})
public class AnnotationConfiguration {

    /**
     * 注入一个Type为User(方法返回值)的bean,bean的名称为user(方法名)
     * initMethod 指定Bean创建后调用的初始化方法
     * destroyMethod 指定Bean在销毁后会调用的方法
     * @return
     */
    @Bean(initMethod = "init", destroyMethod = "destory")
    public User user() {
        return new User();
    }


    /**
     * 测试@Conditional 满足{@link DevelopmentProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
     *
     * @return
     */
    @Bean
    @Conditional({DevelopmentProfileCondition.class})
    public DevelopmentBean developmentService() {
        return new DevelopmentBean();
    }


    /**
     * 满足{@link ProductionProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
     *
     * @return
     */
    @Bean
    @Conditional({ProductionProfileCondition.class})
    public ProductionBean productionService() {
        return new ProductionBean();
    }


    /**
     * 使用FactoryBean工厂来注册组件
     * @return
     */
    @Bean
    public FactoryPrototypeBeanConfiguration factoryPrototypeBeanConfiguration() {
        return new FactoryPrototypeBeanConfiguration();
    }

    /**
     * 使用FactoryBean工厂来注册组件
     * @return
     */
    @Bean
    public FactorySingletonBeanConfiguration factorySingletonBeanConfiguration() {
        return new FactorySingletonBeanConfiguration();
    }


    /**
     * 注册一个实现InitializingBean, DisposableBean接口来指定Bean的初始化和销毁方法的Bean
     * @return
     */
    @Bean
    public InitAndDisposableBean initAndDisposableBean() {
        return new InitAndDisposableBean();
    }

    /**
     * 创建一个通过JSR250 @PostConstruct指定初始化方法/@PreDestroy指定销毁方法的Bean
     * @return
     */
    @Bean
    public PostConstructAndPreDestoryBean postConstructAndPreDestoryBean() {
        return new PostConstructAndPreDestoryBean();
    }


    /**
     * 注入AutowiredBean,名称为autowiredBean2,并将该bean作为默认依赖注入的首选
     * @return
     */
    @Bean
    @Primary
    public AutowiredBean autowiredBean2() {
        return new AutowiredBean();
    }
}
  • 新建一个AutowiredService.java并使用@Service注解交由容器管理,然后注入AutowiredBean
package com.ddf.spring.annotation.service;

import com.ddf.spring.annotation.bean.AutowiredBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * @author DDf on 2018/8/6
 * @Autowired 默认使用Bean的类型去匹配注入,如果找到多个相同类型的Bean,则使用默认名称去获取Bean,Bean的默认名称为类首字母缩写
 * * 也可以配合@Autowired配合@Qualifier注解明确指定注入哪个Bean,还可以在注入Bean的地方使用@Primary,在不指定@Qualifier的情况下,
 * * 默认注入@Primary修饰的Bean,如果Bean不一定存在,可以使用属性required=false,则Bean不存在也不会抛出异常
 * 可以标注在构造器,方法,参数,字段上
 *
 * @Resource 默认使用名称注入Bean,可以使用name属性指定具体要注入的Bean的名称,不支持@Primary,不支持required=false,不支持@Primary
 * @Inject 使用类型去注入,支持@Primary,不支持required=false
 *
 *
 */
@Service
public class AutowiredService {
    @Autowired
    private AutowiredBean autowiredBean;
    public AutowiredBean getAutowiredBean() {
        return autowiredBean;
    }

    @Autowired
    @Qualifier("autowiredBean")
    private AutowiredBean qualifierAutowiredBean;
    public AutowiredBean getQualifierAutowiredBean() {
        return qualifierAutowiredBean;
    }

    public AutowiredService() {
        System.out.println("AutowiredService创建完成。。。。。。。。。。。。");
    }
}
  • 测试见 5.3 综合演示测试结果
5.2 @Resource@Inject

这两个注解也可以完成依赖注入,并且是java规范提供的。区别为@Resource默认是使用名称来注入组件的,并且不支持@Primary,也不支持required=false,有一个属性名为name可以指定要注入的Bean的名称;@Inject@Autowired类似,按照类型注入,支持@Primary,不支持required=false

  • 修改AutowiredService.java,加入@Resource@Inject的注入代码
package com.ddf.spring.annotation.service;

import com.ddf.spring.annotation.bean.AutowiredBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.inject.Inject;

/**
 * @author DDf on 2018/8/6
 * @Autowired 默认使用Bean的类型去匹配注入,如果找到多个相同类型的Bean,则使用默认名称去获取Bean,Bean的默认名称为类首字母缩写
 * * 也可以配合@Autowired配合@Qualifier注解明确指定注入哪个Bean,还可以在注入Bean的地方使用@Primary,在不指定@Qualifier的情况下,
 * * 默认注入@Primary修饰的Bean,如果Bean不一定存在,可以使用属性required=false,则Bean不存在也不会抛出异常
 * 可以标注在构造器,方法,参数,字段上
 *
 * @Resource 默认使用名称注入Bean,可以使用name属性指定具体要注入的Bean的名称,不支持@Primary,不支持required=false,不支持@Primary
 * @Inject 使用类型去注入,支持@Primary,不支持required=false
 *
 *
 */
@Service
public class AutowiredService {
    @Autowired
    private AutowiredBean autowiredBean;
    public AutowiredBean getAutowiredBean() {
        return autowiredBean;
    }

    @Autowired
    @Qualifier("autowiredBean")
    private AutowiredBean qualifierAutowiredBean;
    public AutowiredBean getQualifierAutowiredBean() {
        return qualifierAutowiredBean;
    }

    @Resource(name = "autowiredBean")
    private AutowiredBean resourceAutowiredBean;
    public AutowiredBean getResourceAutowiredBean() {
        return resourceAutowiredBean;
    }


    @Resource(name = "autowiredBean2")
    private AutowiredBean resourceAutowiredBean2;
    public AutowiredBean getResourceAutowiredBean2() {
        return resourceAutowiredBean2;
    }

    @Inject
    private UserService userService;
    public UserService getUserService() {
        return userService;
    }

    public AutowiredService() {
        System.out.println("AutowiredService创建完成。。。。。。。。。。。。");
    }
}
  • 测试见 5.3 综合演示测试结果
5.3 综合演示测试结果
  • 修改主启动类Application.java,增加测试依赖注入的方法testAutowired()
package com.ddf.spring.annotation;

import com.ddf.spring.annotation.service.AutowiredService;
import com.ddf.spring.annotation.service.LazyBeanService;
import com.ddf.spring.annotation.service.PrototypeScopeService;
import com.ddf.spring.annotation.service.UserService;
import com.ddf.spring.annotation.bean.AutowiredBean;
import com.ddf.spring.annotation.bean.FactoryPrototypeBean;
import com.ddf.spring.annotation.bean.FactorySingletonBean;
import com.ddf.spring.annotation.configuration.AnnotationConfiguration;
import com.ddf.spring.annotation.entity.User;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Primary;

/**
 * @author DDf on 2018/7/19
 */
public class Application {
    public static void main(String[] args) {
        System.out.println("-----------------------IOC容器初始化-------------------------");
        // 创建一个基于配置类启动的IOC容器,如果主配置类扫描包的路径下包含其他配置类,则其他配置类可以被自动识别
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationConfiguration.class);
        System.out.println("-----------------------IOC容器初始化完成-------------------------\n");
        // 获取当前IOC中所有bean的名称,即使是懒加载类型的bean也会获取到
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        // 打印当前IOC中对应名称的bean和bean的类型
        for (String name : definitionNames) {
            // 这个会影响到测试懒加载的效果,如果需要测试懒加载,这行代码需要注释掉,因为getBean方法一旦调用则会初始化
            Object bean = applicationContext.getBean(name);
            System.out.println("bean name:" + name + ", type: " + bean.getClass());
        }

        // 测试@Scope bean的作用域
        testPrototypeScopeService(applicationContext);
        // 测试单实例bean的@Lazy懒加载
        testLazyBeanService(applicationContext);
        // 测试FactoryBean接口导入单实例与Prototype作用域的组件
        testFactoryBeanPrototypeBean(applicationContext);
        // 测试@PropertySource和@Value属性赋值
        testPropertySourceValue(applicationContext);
        // 测试@Autowired注入多个相同类型的Bean
        testAutowired(applicationContext);

        // 销毁容器
        applicationContext.close();
    }


    /**
     * 测试@Scope bean的作用域
     *
     * @param applicationContext
     */
    public static void testPrototypeScopeService(ApplicationContext applicationContext) {
        System.out.println("\n-----------------------测试@Scope开始-------------------------");
        UserService userService = (UserService) applicationContext.getBean("userService");
        UserService userService1 = applicationContext.getBean(UserService.class);
        System.out.println("默认单实例bean UserService是否相等 " + (userService == userService1));

        PrototypeScopeService prototypeScopeService = applicationContext.getBean(PrototypeScopeService.class);
        PrototypeScopeService prototypeScopeService1 = applicationContext.getBean(PrototypeScopeService.class);
        System.out.println("PrototypeScopeService prototype scope作用域是否相等: " + (prototypeScopeService == prototypeScopeService1));
        System.out.println("-----------------------测试@Scope结束-------------------------\n");
    }

    /**
     * 测试单实例bean的懒加载,只有等使用的时候再创建实例。
     * IOC容器启动后不会创建该bean的实例,如果是在该方法中才创建这个bean的实例,并且获得的两个bean是同一个的话,则测试通过。
     */
    public static void testLazyBeanService(ApplicationContext applicationContext) {
        System.out.println("\n---------------测试单实例bean的@Lazy懒加载开始----------------------");
        LazyBeanService lazyBeanService = applicationContext.getBean(LazyBeanService.class);
        LazyBeanService lazyBeanService1 = applicationContext.getBean(LazyBeanService.class);
        System.out.println("lazyBeanService==lazyBeanService1?: " + (lazyBeanService == lazyBeanService1));
        System.out.println("---------------测试单实例bean的@Lazy懒加载结束----------------------\n");
    }


    /**
     * 测试通过FactoryBean接口导入单实例与Prototype作用域的组件,根据打印可以看出FactoryBean创建的单实例Bean都是懒加载的
     * @param applicationContext
     */
    public static void testFactoryBeanPrototypeBean(ApplicationContext applicationContext) {
        System.out.println("\n----------测试通过FactoryBean注册单实例和Prototype作用域的组件开始----------");
        FactorySingletonBean factorySingletonBean = applicationContext.getBean(FactorySingletonBean.class);
        FactorySingletonBean factorySingletonBean1 = applicationContext.getBean(FactorySingletonBean.class);

        FactoryPrototypeBean factoryPrototypeBean = applicationContext.getBean(FactoryPrototypeBean.class);
        FactoryPrototypeBean factoryPrototypeBean1 = applicationContext.getBean(FactoryPrototypeBean.class);

        System.out.println("单实例factorySingletonBean==factorySingletonBean1?" + (factorySingletonBean==factorySingletonBean1));

        System.out.println("Prototype作用域factoryPrototypeBean==factoryPrototypeBean1?" + (factoryPrototypeBean==factoryPrototypeBean1));
        System.out.println("----------测试通过FactoryBean注册单实例和Prototype作用域的组件结束----------\n");
    }

    /**
     * 测试通过@PropertySource和@Value注解来对属性进行赋值
     * @param applicationContext
     */
    public static void testPropertySourceValue(ApplicationContext applicationContext) {
        System.out.println("\n---------------测试@PropertySource和@Value赋值开始----------------");
        User user = applicationContext.getBean(User.class);
        System.out.println("user属性为: " + user.toString());
        System.out.println("---------------测试@PropertySource和@Value赋值结束----------------\n");

    }

    /**
     * 测试在IOC容器中存在两个相同类型的Bean,但是Bean的名称不一致
     * 在这种情况下,使用@Autowired将该Bean注入到另外一个容器中
     * @Autowired 默认使用Bean的类型去匹配注入,如果找到多个相同类型的Bean,则使用默认名称去获取Bean,Bean的默认名称为类首字母缩写
     * 也可以配合@Autowired配合@Qualifier注解明确指定注入哪个Bean,还可以在注入Bean的地方使用@Primary,在不指定@Qualifier的情况下,
     * 默认注入哪个Bean {@link AutowiredService}
     * @param applicationContext
     */
    public static void testAutowired(ApplicationContext applicationContext) {
        System.out.println("\n--------------测试autowired注入多个相同类型的类开始-----------------");
        AutowiredBean autowiredBean = (AutowiredBean) applicationContext.getBean("autowiredBean");
        AutowiredBean autowiredBean2 = (AutowiredBean) applicationContext.getBean("autowiredBean2");
        System.out.println("autowiredBean: " + autowiredBean);
        System.out.println("autowiredBean2: " + autowiredBean2);
        System.out.println(autowiredBean == autowiredBean2);

        /**
         * 这里已做更改,修改了默认注入 {@link com.ddf.spring.annotation.configuration.AnnotationConfiguration.autowiredBean2}
         */
        AutowiredService autowiredService = applicationContext.getBean(AutowiredService.class);
        AutowiredBean autowiredServiceBean = autowiredService.getAutowiredBean();
        System.out.println("使用@Primay后AutowiredService默认注入bean: " + autowiredServiceBean);

        AutowiredBean autowiredServiceBean2 = autowiredService.getQualifierAutowiredBean();
        System.out.println("使用@Qualifier明确注入Bean: " + autowiredServiceBean2);

        // 使用@Resource注入
        AutowiredBean resourceAutowiredBean = autowiredService.getResourceAutowiredBean();
        System.out.println("使用@Resource注入autowiredBean: " + resourceAutowiredBean);
        AutowiredBean resourceAutowiredBean2 = autowiredService.getResourceAutowiredBean2();
        System.out.println("使用@Resource注入autowiredBean2: " + resourceAutowiredBean2);

        // 使用@Inject注入
        UserService userService = autowiredService.getUserService();
        System.out.println("使用@Inject注入UserService: " + userService);

        System.out.println("--------------测试autowired注入多个相同类型的类开始-----------------\n");
    }
}
  • 打印日志如下,不相关日志已过滤
// 过滤。。。
--------------测试autowired注入多个相同类型的类开始-----------------
autowiredBean: com.ddf.spring.annotation.bean.AutowiredBean@77e4c80f
autowiredBean2: com.ddf.spring.annotation.bean.AutowiredBean@1d119efb
false
使用@Primay后AutowiredService默认注入bean: com.ddf.spring.annotation.bean.AutowiredBean@1d119efb
使用@Qualifier明确注入Bean: com.ddf.spring.annotation.bean.AutowiredBean@77e4c80f
使用@Resource注入autowiredBean: com.ddf.spring.annotation.bean.AutowiredBean@77e4c80f
使用@Resource注入autowiredBean2: com.ddf.spring.annotation.bean.AutowiredBean@1d119efb
使用@Inject注入UserService: com.ddf.spring.annotation.service.UserService@4b5d6a01
--------------测试autowired注入多个相同类型的类开始-----------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值