四、自動裝配
1.@Autowried&@Qualifier和@Primary
@Autowried是Spring2.5定義的自動裝配的註解,它可以對類成員變量、方法及構造函數進行標註,完成自動裝配的工作。 使用 @Autowired的使用來消除 set ,get方法。@Autowired 標註在方法上表示當前方法的自定義參數從容器中賦值,ioc容器默認賦值時,需要調用無參構造器後,再進行默認賦值,如果當前類只有一個有參的構造器,則@Autwried可以省略,並且該構造器的參數也默認從ioc容器中獲取。
我們創建Color接口、以及它的實現類Red和Bule來介紹@Autowried&@Qualifier和@Primary的用法
Color接口
public interface Color {
}
Red實現類
@Component
public class Red implements Color {
public Red() {
System.out.println("這是Red的 構造器");
}
}
Flower類
@Component
public class Flower {
@Autowired
private Color color;
@Override
public String toString() {
return "Folwer{" +"color=" + color +'}';
}
}
配置類 AutowriedConfig
@Configuration
@ComponentScan("com.daxiong.pojo.Autowired")
public class AutowriedConfig {
}
測試類
public class AutowriedConfigTest {
private AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AutowriedConfig.class);
@Test
public void testAutowired1() {
Flower bean = annotationConfigApplicationContext.getBean(Flower.class);
System.out.println(bean);
}
}
此時我們只在Spring容器中注入的一個Color的實現類Red,測試結果
添加Bule類
@Component
public class Bule implements Color {
public Bule() {
System.out.println("這是Bule 的 構造器");
}
}
運行結果:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'flower': Unsatisfied dependency expressed through field 'color'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected single matching bean but found 2: bule,red
.....
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected single matching bean but found 2: bule,red
出現No qualifying bean of type ‘com.daxiong.pojo.Autowired.Color’ available的異常,原因是@Autowried是按照類型注入的,我們在Flower中注入的Color對象沒有指定類型,Spring容器不知道到底應該注入哪一個對象的原因。解決辦法有以下幾種方法:
使用@Qualifier註解,明確的指定注入類型
@Qualifier(value="red") private Color color;
使用@Primary註解,默認指定的類型
@Primary @Component public class Red implements Color { public Red() { System.out.println("這是Red的 構造器"); } }
修改參數名
@Component public class Flower { //修改color的屬性名爲red @Autowired private Color red; @Override public String toString() { return "Folwer{" +"color=" + red +'}'; }
運行結果:
注意點:
如果在自動裝配時。Spring容器中沒有註冊對應的Bean,就會報錯
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.daxiong.pojo.Autowired.Color' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
我們也只需要在@Autowried後加上(required=true)即可
2.@Resource&@Inject
@Resource和@Inject分別是在JSR250和JSR330規範中定義的註解,在Spring中也得到了支持使用方法和@Autowried的類似
@Resource默認是按照屬性來裝配的,沒有支持@Primary和reuired
@Inject支持@Primary,但時不支持reuired,需要導入javax.Inject包
3.Aware注入Spring底層組件&原理
自定義組件想要使用Spring容器底層的一些組件比如ApplicationContext,BeanFactory,等等,都可以通過實現XXXAware,在創建對象時,會把調用接口規定的方法把指定的組件裝配進去。
實現原理,這些XXXAware接口,都有對應的XXXprocessor來處理
如ApplicationContextAware有ApplicationContextAwareProcessor來處理Spring源碼:
//實現了BeanPostProcessor接口,所以會在組件初始化的識貨調用
class ApplicationContextAwareProcessor implements BeanPostProcessor {
//在組件賦值前調用
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
//判斷是否爲對應接口類型
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
//進行賦值操作
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
//對應的接口進行賦值操作
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
}