1 @Autowired 幹嘛的?
用來執行依賴注入.每當一個Spring管理的bean發現有該註解時,會直接注入相應的另一個Spring管理的bean.
1.1 不同地放置有不同作用
- 屬性
Spring將通過掃描自定義的package或通過在配置文件中直接查找bean - 方法
使用@Autowired註解的每個方法都要用到依賴注入
但要注意的是,簽名中呈現的所有對象都必須是Spring所管理的bean
如果你有一個方法,比如setTest(Article article, NoSpringArticle noSpringArt)
,其中只有一個參數 (Article article)是由Spring管理的,那麼就將拋出一個org.springframework.beans.factory.BeanCreationException異常
這是由於Spring容器裏並沒有指定的一個或多個參數所指向的bean,所以也就無法解析它們
1.2 bean的注入方式
- 名稱
bean解析是通過bean名稱 - 類型
解析基於bean的類型
1.3 @Qualifier 協作
如下相同類型的bean
<bean name="article1" class="com.sss.Article">
<property name="text" value="Content of the 1st Article" />
</bean>
<bean name="article2" class="com.sss.Article">
<property name="text" value="Content of the 2nd Article" />
</bean>
假如只是一個簡單的@Autowired,Spring根本不知道你要注入哪個bean。這就需要@Qualifier(value =“beanName”)協作.
譬如,要從 com.javaedge.Article
類型的bean中區分article1,article2:
@Qualifier(value="article1")
@Autowired
private Article firstArticle;
@Qualifier(value="article2")
@Autowired
private Article secondArticle;
2 優雅地使用@Autowired
啓動自動注入
<context:annotation-config />
放在應用程序上下文配置。可以使在遇到@Autowired註解時啓用依賴注入
- bean
// beans first
public class Comment {
private String content;
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return this.content;
}
}
// sample controller
@Controller
public class TestController {
@Qualifier(value="comment1")
@Autowired
private Comment firstComment;
@Qualifier(value="comment2")
@Autowired
private Comment secondComment;
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test() {
System.out.println("1st comment text: "+firstComment.getText());
System.out.println("2nd comment text: "+secondComment.getText());
return "test";
}
}
// no-Spring managed class
public class TestNoSpring {
@Autowired
private Comment comment;
public void testComment(String content) {
if (comment == null) {
System.out.println("Comment's instance wasn't autowired because this class is not Spring-managed bean");
} else {
comment.setContent(content);
System.out.println("Comment's content: "+comment.getContent());
}
}
}
- 配置
<bean name="comment1" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 1st comment" />
</bean>
<bean name="comment2" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 2nd comment" />
</bean>
打開http://localhost:8080/test來運行TestController
TestController的註解字段正確地自動注入,而TestNoSpring的註解字段並沒有注入進去
1st comment text: Content of the 1st comment
2nd comment text: Content of the 2nd comment
Comment's instance wasn't autowired because this class is not Spring-managed bean
哪裏不對 ?TestNoSpring類不由Spring所管理
這就是爲什麼Spring不能注入Comment實例的依賴
3 隱藏在@Autowired註解背後的祕密
Spring管理可用於整個應用程序的Java對象bean,我們不需要處理他們的生命週期(初始化,銷燬)。該任務由此容器來完成。
該上下文具有入口點,在Web應用程序中,是dispatcherservlet
。
容器(也就是該上下文)會在它那裏被啓動並且所有的bean都會被注入
看<context:annotation-config />的定義
<xsd:element name="annotation-config">
<xsd:annotation>
<xsd:documentation><![CDATA[
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext
for information on code-based alternatives to bootstrapping annotation-driven support.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
類內部的註解,如@Autowired、@Value、@Required、@Resource以及Web Serivce相關的註解,是容器對Bean對象實例化和依賴注入時,通過容器中註冊的Bean後置處理器處理這些註解的
所以配置了上面這個配置(<context:component-scan>假如有配置這個,那麼就可以省略<context:annotation-config />
)後,將隱式地向Spring容器註冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及這4個專門用於處理註解的Bean後置處理器。
當 Spring 容器啓動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean
當發現 Bean 中擁有@Autowired 註解時就找到和其匹配(默認按類型匹配)的 Bean
並注入到對應的地方中去。
4 源碼分析
通過org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor可以實現依賴自動注入
通過這個類來處理@Autowired @Value Spring
它也可以管理JSR-303的@Inject
- 在
AutowiredAnnotationBeanPostProcessor
構造函數中定義要處理的註解
之後,有幾種方法對@Autowired處理
第一個,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自動注入類的所有屬性。它通過分析所有字段和方法並初始化org.springframework.beans.factory.annotation.InjectionMetadata類的實例來實現。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
//分析所有字段
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//findAutowiredAnnotation(field)此方法後面會解釋
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
//分析所有方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
//返回一個InjectionMetadata初始化的對象實例
return new InjectionMetadata(clazz, elements);
}
...
/**
* 'Native' processing method for direct calls with an arbitrary target instance,
* resolving all of its fields and methods which are annotated with {@code @Autowired}.
* @param bean the target instance to process
* @throws BeanCreationException if autowiring failed
*/
public void processInjection(Object bean) throws BeanCreationException {
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
try {
metadata.inject(bean, null, null);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
}
InjectionMetadata
類包含要注入的元素的列表
注入是通過Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object … args)方法完成的
此過程直接在AutowiredAnnotationBeanPostProcessor
的方法中調用
public void processInjection(Object bean) throws BeanCreationException
它將所有可注入的bean檢索爲InjectionMetadata實例,並調用它們的inject()方法
public class InjectionMetadata {
...
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//看下面靜態內部類的方法
element.inject(target, beanName, pvs);
}
}
}
...
public static abstract class InjectedElement {
protected final Member member;
protected final boolean isField;
...
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
//具體的注入看此處咯
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
...
}
}
findAutowiredAnnotation(AccessibleObject ao)
分析屬於一個字段或一個方法的所有註解來查找@Autowired註解。如果未找到@Autowired註解,則返回null,字段或方法也就視爲不可注入。