一、包扫描
前文中配置类里显示的构造了类对象,而创建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了。