Spring开发注解-实现方法、构造器位置的自动装配

Spring开发注解-实现方法、构造器位置的自动装配

Autowired源码解析:

可以看出@Autowired注解不仅可以标注在字段上,而且还可以标注在构造方法CONSTRUCTOR、实例方法ElementType.METHOD以及参数ElementType.PARAMETER上。

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

练习

新建一个Boss类,在Boss类中有一个Car类的引用,并且我们使用@Component注解将Dog类加载到IOC容器中,如下所示,注意,Car类上也要标注@Component注解,即它也要被加载到IOC容器中

package com.ralph.bean;

import org.springframework.stereotype.Component;

// 默认加在IOC容器中的组件,容器启动会调用无参构造器创建对象,然后再进行初始化、赋值等操作
@Component
public class Boss {
    private Car car;

    public Boss(Car car) {
        this.car = car;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car=" + car +
                '}';
    }
}

新建好以上Boss类之后,我们还需要在MainConfigOfAutowired配置类的@ComponentScan注解中进行配置,使其能够扫描com.ralph.bean包下的类,如下所示。

package com.ralph.config;

import com.ralph.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
@ComponentScan({"com.ralph.service","com.ralph.dao","com.ralph.controller","com.ralph.bean"})
public class MainConfigOfAutowired {

    @Primary
    @Bean("bookDao2")
    public BookDao bookDao() {
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }

}

让set方法通过自动装配,我们可以将@Autowired注解标注在setter方法上

    @Autowired
    public void setCar(Car car) {
        this.car = car;
    }

当@Autowired注解标注在方法上面,spring容器在创建当前对象的时候,就会调用相应的方法为对象赋值,如果标注的方法存在参数时,那么方法使用的参数和自定义类型的值,需要从IOC容器中获取

测试:

    @Test
    public void testForAutoWiredMethod(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);
        applicationContext.close();

    }
OUTPUT:
Boss{car=com.ralph.bean.Car@4b5d6a01}

说明已经获取到了car的信息,也就是说可以将@Autowired注解标注在方法上。

为了验证最终的输出结果是否是从IOC容器中获取的,我们可以在Test类的方法中直接获取Car对象的信息

    @Test
    public void testForAutoWiredMethod(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);

        Car bean = applicationContext.getBean(Car.class);
        System.out.println(bean);
        applicationContext.close();

    }
OUTPUT: 可以看出两个内存地址是一样的
Boss{car=com.ralph.bean.Car@48e4374}
com.ralph.bean.Car@48e4374

这已然说明在Boss类中通过@Autowired注解获取到的Car对象和直接从IOC容器中获取到Car对象是同一个对象。

标注在构造方法上

在上面自动装配用在了普通方法上面 我们在boss类使用了@Component 注解,此时Spring会默认将该类加载到IOC容器中,ioc容器启动的时候会默认调用bean无参构造器创建对象,然后依次初始化、赋值

其实,我们为Boss类添加一个有参构造方法,然后去除setCar()方法上的@Autowired注解,将@Autowired注解标注在有参构造方法上,并在构造方法中打印一条信息

    @Test
    public void testForAutoWiredMethod(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);

        Car bean = applicationContext.getBean(Car.class);
        System.out.println(bean);
        applicationContext.close();

    }

说明IOC容器在启动的时候调用了Boss类的有参构造方法。并且还可以从输出的如下两行信息中看出,通过Boss类的toString()方法打印出的Car对象和直接从IOC容器中获取的Car对象是同一个对象。

OUTPUT:
This is Boss have params constructor
Boss{car=com.ralph.bean.Car@9353778}
com.ralph.bean.Car@9353778

  • 使用@Autowired注解标注在构造方法上面的时候,构造方法中的参数对象也是从IOC容器中获取的

    this.car = car;
    
  • 使用@Autowired注解标注在构造方法上时,如果组件中只有一个有参构造方法,那么这个有参构造方法上的@Autowired注解可以省略,并且参数位置的组件还是可以自动从IOC容器中获取。


标注在参数上

我们也可以将@Autowired注解标注在参数上,例如,在Boss类中我们将构造方法上的@Autowired注解标注在构造方法的参数上,如下所示。

public Boss(@Autowired Car car) {
    this.car = car;
    System.out.println("Boss...有参构造器");
}


or
public void setCar(@Autowired Car car) {
    this.car = car;
}

最终的效果与标注在字段、实例方法和构造方法上的效果都是一样的

于是,我们可以得出结论:无论@Autowired注解是标注在字段上、实例方法上、构造方法上还是参数上,参数位置的组件都是从IOC容器中获取。

如果Spring的bean中只有一个有参构造方法,并且这个有参构造方法只有一个参数,这个参数还是IOC容器中的对象,当@Autowired注解标注在这个构造方法的参数上时,那么我们可以将其省略掉,如下所示。


public Boss(/*@Autowired*/ Car car) {
    this.car = car;
    System.out.println("Boss...有参构造器");
}

从输出的结果信息中可以看出,同样输出了下面的三行信息。

This is Boss have params constructor
Boss{car=com.ralph.bean.Car@7e0b85f9}
com.ralph.bean.Car@7e0b85f9

标注在方法位置

创建一个Color类

package com.ralph.bean;

public class Color {
    public Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Color{" +
                "car=" + car +
                '}';
    }
}

然后,我们在MainConfigOfAutowired配置类中实例化Color类,如下所示。

@Bean
public Color color() {
    Color color = new Color();
    return color;
}

在测试类中输出Color对象

@Test
public void testForAutoWired(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
    Color bean = applicationContext.getBean(Color.class);
    System.out.println(bean);
    applicationContext.close();

}
OUTPUT:
Color{car=null}

说明此时的Color对象中的Car对象为空。此时,我们可以将Car对象作为一个参数传递到MainConfigOfAutowired配置类的color()方法中,并且将该Car对象设置到Color对象中,如下所示

    @Bean
    public Color color(@Autowired Car car){
        Color color = new Color();
        color.setCar(car);
        return color;
    }

再次运行测试类:

OUTPUT:
Color{car=com.ralph.bean.Car@31d7b7bf}

说明Car对象被成功创建并设置到Color对象中了。

至此,我们可以得出结论:如果方法只有一个IOC容器中的对象作为参数,当@Autowired注解标注在这个方法的参数上时,我们可以将@Autowired注解省略掉。也就说@Bean注解标注的方法在创建对象的时候,方法参数的值是从IOC容器中获取的,此外,标注在这个方法的参数上的@Autowired注解可以省略。

其实,我们用到最多的还是把@Autowired注解标注在方法位置,即使用@Bean注解+方法参数这种形式,此时,该方法参数的值从IOC容器中获取,并且还可以默认不写@Autowired注解,因为效果都是一样的,都能实现自动装配!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值