Spring (二)扫描与依赖注入

一、包扫描

前文中配置类里显示的构造了类对象,而创建bean还有一种更为简便的方式,即包扫描,仅需在配置类上添加@ComponentScan,即可扫描当前配置文件所在包及子包下的类,将带有@Component注解的类创建并注入到Spring容器中。

package com.zdg.beanfit;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.zdg.component.ChineseController;
@Configuration
@ComponentScan("com.zdg.component")
public class ScanConfig {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
                new AnnotationConfigApplicationContext(ScanConfig.class);
        System.out.println(context.getBean("p"));
        System.out.println(context.getBean(ChineseController.class));

        context.close();
    }
}

这里@ComponentScan中定义了包位置,则会去扫描指定的包,包中的类也需要添加相应的注解来控制是否创建对象。可选的注解有@Component、@Controller、@Service、@Repository,这些注解名称不同,实际仅是为了标明类的功能类型,本质上都是Component。如@Controller注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     */
    @AliasFor(annotation = Component.class)
    String value() default "";

}

可以看到该注解上使用了@Component注解,其余几个也是一样,另外value属性用于标明bean的id即bean的名称。

二、依赖注入

依赖注入可以使用@Autowired注解,该注解可以声明在方法上或是构造函数上:

@Component
public class Person {
    private Pet pet;
    @Autowired
    public void setPet(Pet pet) {
        this.pet = pet;
    }
    public Pet getPet() {
        return pet;
    }
}

以上代码声明了一个宠物对象,Pet是一个借口,仅声明了一个print函数,另外创建了一个实现类:

@Component
public class Pig implements Pet{

    public void print() {
        System.out.println(this);
    }

}

此时Spring容器会将容器中的Pig注入到Person中:

@Configuration
@ComponentScan("com.zdg.component")
public class ScanConfig {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
                new AnnotationConfigApplicationContext(ScanConfig.class);
        Person p = context.getBean(Person.class);
        p.getPet().print();//com.zdg.component.Pig@345965f2
        context.close();
    }
}

运行后打印值如代中的注释相同,如此便完成了一个简单的依赖注入,而整个过程并未显示调用new关键字创建对象,也没有调用任何set方法注入值,整个过程由Spring容器自动完成。

三、指定注入

上面的代码中Pet的实现类仅有一个,如果再加一个Cat实现类,那注入时会选择哪一个呢,Spring也不知道,因此需要我们指定一个bean注入,这里有三种方法实现:
1、@Primary
在组件上添加@Primary注解,在注入时若有多个可选对象,则会在注入时优先选择该类注入:

@Component
@Primary
public class Pig implements Pet{
    public void print() {
        System.out.println(this);
    }
}

2、@Qualifier
使用该注解可以显示指定一个bean注入,此时存在@Primary注解也会注入@Qualifier指定的bean(@Primary仅在未指定注入对象时优先选用)

@Component()
public class Person {
    private Pet pet;
    @Autowired
    @Qualifier("cat")
    public void setPet(Pet pet) {
        this.pet = pet;
    }
    public Pet getPet() {
        return pet;
    }
}

3、自定义注解:
除了@Qualifier外,还可以自定义注解实现指定bean注入,注解定义如下:

@Target({ElementType.FIELD, ElementType.METHOD, 
    ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PetCat {
}

只需添加@Qualifier注解,另外两个注解从Qualifier注解中复制过来即可。
使用方式:
第一步,在组件定义上添加自定义注解

@Component
@PetCat
public class Cat implements Pet {
    public void print() {
        System.out.println(this);
    }
}

第二步,在自动注入的函数上添加自定义注解:

@Component()
public class Person {
    private Pet pet;
    @Autowired
    @PetCat
    public void setPet(Pet pet) {
        this.pet = pet;
    }
    public Pet getPet() {
        return pet;
    }
}

这样在Spring选择注入对象时就会选择我们指定的bean了。

猜你喜欢

转载自blog.csdn.net/qq_38071004/article/details/81744176