一、屬性賦值
- 屬性賦值相關的注解
@Value
@PropertySource
springboot中的@ConfigurationProperties(prefix = "xxx")
二、自動裝配
- 概念:Spring利用依賴注入(DI),完成對IOC容器中中各個組件的依賴關系賦值
1、@Autowired:自動注入
1)、默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class);找到就賦值
2)、如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找applicationContext.getBean("bookDao")
3)、@Qualifier("bookDao"):使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名
4)、自動裝配默認一定要將屬性賦值好,沒有就會報錯;可以使用@Autowired(required=false);
5)、@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean;也可以繼續使用@Qualifier指定需要裝配的bean的名字
2、@Resource(JSR250)和@Inject(JSR330)[java規范的注解]
1、@Resource:可以和@Autowired一樣實現自動裝配功能;默認是按照組件名稱進行裝配的;沒有能支持@Primary功能。
2、@Inject:需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
總結:
- @Autowired:Spring定義的; @Resource、@Inject都是java規范
- AutowiredAnnotationBeanPostProcessor解析完成自動裝配功能
三、自定義組件想要使用Spring容器底層的一些組件
- 例如:ApplicationContext,BeanFactory,xxx
1、Aware接口
- Aware是一個具有標識作用的超級接口,實現該接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通過回調。總之:直接或間接實現了這個接口的類,都具有被spring容器通知的能力。
-
繼承接口:
Aware接口繼承接口
- 可以知道這些xxxAware接口都只有一個setxxx方法,目的就是給實現該接口的類的xxx屬性設置值。在spring中這些實現xxxAware接口的類是如何實現感應并設置xxx屬性的值的呢,答案就是在spring容器中在工廠類創建實例后使用instanceof判斷實例是否屬于xxxAware接口的實例,如果結果是true的話,那么spring容器類就會調用實例的setXxx()方法給實例的xxx屬性設置值。簡單來說就是實現這些 Aware接口的Bean在被初始之后,可以從Spring容器中取得一些相對應的資源,例如實現BeanFactoryAware接口的Bean在初始后,Spring容器將會注入BeanFactory的實例,而實現ApplicationContextAware接口的Bean,在Bean被初始后,將會被注入 ApplicationContext的實例等等。
- 注意:
有六大類xxxAware是由spring容器自動注冊在容器中的,應用程序不需要再次的在容器中注入了,但是如果我們實現其他的xxxAware,還必須在容器中注入才能使用,從ApplicationContextAwareProcessor源碼可以解讀出,這六類特殊的xxxAware是:
- @see org.springframework.context.EnvironmentAware
- @see org.springframework.context.EmbeddedValueResolverAware
- @see org.springframework.context.ResourceLoaderAware
- @see org.springframework.context.ApplicationEventPublisherAware
- @see org.springframework.context.MessageSourceAware
- @see org.springframework.context.ApplicationContextAware
2、從實現到原理再到實現
- 前面可知實現xxxAware接口主要是為了獲取spring的一些特性
(1)自己實現一個接口獲取spring的特性,比如BeanFactoryAware
public class Animal implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
- 注意:我們的Animal 類實現了aware接口,如果我們直接在應用中new一個Animal 的對象,當然是拿不到beanFactory變量的,我們必須在spring的配置文件中聲明我們的fruit對象才行,也就是說Animal 對象必須交給容器進行管理,容器幫你把各種aware接口中想要注入的對象設置到bean中。具體看容器管理aware接口的代碼實現,代碼在AbstractAutowireCapableBeanFactory的initializeBean方法中:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 開始Bean初始化前處理、初始化、初始化后處理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可以看出來,aware接口的各種處理是在屬性設置完成之后、bean初始化之前完成的。顯然的,如果我們直接new出來一個bean,這些框架性的特性是沒有使用到的。但是上面提到的六中特殊的xxxAware,比如ApplicationContextAware,可以完成自動化在容器中進行接口注入,原來在應用中創建上下文容器時會注冊一個BeanPostProcessor------ApplicationContextAwareProcessor,在這個類里面進行了context的注入,這樣我們就能能夠拿到bean中的context對象:
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;
}
然后在AbstractApplicationContext.prepareBeanFactory方法中,進行對ApplicationContextAwareProcessor的注入。
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
3、自定義aware接口實現
- 知道原理后我們要實現自定義aware接口實現,需要完成下面兩個步驟:
1.實現我們aware接口的postprocessor,并在容器中注冊;
2.bean實體類集成我們自定義的aware接口并實現 - 具體案例實現:
(1)自定義aware接口:
public interface AppleAware {
void setApple(Apple a);
}
(2)自定義Processor實現BeanPostProcessor接口
public class AppleAwarePostProcessor implements BeanPostProcessor {
private Apple a;
public AppleAwarePostProcessor(Apple a) {
this.a = a;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof AppleAware) {
((AppleAware) bean).setApple(a);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
return bean;
}
}
(3)實現AppleAware 接口完成自定義bean注入
public class Market implements AppleAware {
private Apple a;
@Override
public void setApple(Apple a) {
this.a = a;
}
public String getName() {
return a.getName();
}
}
(4)測試
- 一定要把我們的BeanPostProcessor加入到當前容器中,這一點非常重要
public class TestAware {
public static void main(String args[]) {
ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
BeanPostProcessor bpp = new AppleAwarePostProcessor((Apple)beanFactory.getBean("apple"));
// 工廠對象中加入我們自定義的BeanPostProcessor
beanFactory.addBeanPostProcessor(bpp);
Market market = (Market) beanFactory.getBean("market");
System.out.println(market.getName());
}
}