使用了那么久Spring,一下子问我Autowired注解使用条件,答不上来吧,看了Spring源码,一点点收货;
废话少说,要是Autowired生效,需要注册BeanPostProcessor,你说我没注册也能用啊,那你一定用了<context:annotation-config>或者<context:component-scan base-package="扫描包名/>这两个注解吧;
简单的测试代码(两个类 Person 以及 Pet ,一个Person类持有一个Pet类的关系)
Person类:
package com.lvbinbin.autowired; import org.springframework.beans.factory.annotation.Autowired; public class Person { private String name; @Autowired private Pet pet; public String toString() { return "Person name:" + name + ",Pet:" + pet; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Pet类:
package com.lvbinbin.autowired; public class Pet { private String name; public String toString() { return "Pet name:"+name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Spring的配置文件(将Person以及Pet放到Spring容器里,或者通过包扫描加入容器)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 7 8 <bean id="person1" class="com.lvbinbin.autowired.Person"> 9 <property name="name" value="lvbinbin"></property> 10 </bean> 11 12 <bean id="pet1" class="com.lvbinbin.autowired.Pet"> 13 <property name="name" value="xiaobinggan"/> 14 </bean> 15 </beans>
简单写个类测试一下:
1 package com.lvbinbin.autowired; 2 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 public class TestCases { 6 7 public static void main(String[] args) { 8 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/lvbinbin/autowired/spring.xml"); 9 Person p1=(Person) context.getBean("person1"); 10 System.out.println(p1); 11 } 12 }
以上代码,测试发现没有注入Pet属性; 也说明了 XML文件 property注入属性需要有对应的Setter Getter方法;
在Spring配置文件中加入下面几句话之一,Autowired就可以生效: <bean id="aabp" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
或者 <context:annotation-config/>
或者 <context:component-scan base-package="包路径"/>
其中包路径随意写也能使用Autowired注解生效,但是不建议写无意义的路径;
额外注意几点: 1. Autowired注解只有一个属性 required 可选值 false / true : 默认为true ,如果实例化该属性时候,IOC容器即BeanFactory中没有可以注入的,抛出异常 ;
设置为false ,实例化该属性时候 容器里没有该类型的bean 同样可以运行 ;
2.Autowired注解的属性可以有setter getter方法;底层是通过反射设置上的值,setter getter方法需不需要都可以成功 ;
3.Autowired注解可以标注在属性、或者方法上, 但是属性和方法都不允许为 static 类型;
4.Autowired注解可以注入一些Spring默认配置上的,ApplicationContext、BeanFactory、Enviroment等等对象;
5.Autowired注解标注在方法上时,方法入参需要都在SpringIOC容器中存在,该类型对象有一个不存在就会抛出异常
偷懒给Person类添加一些public属性;
测试main方法如下:
1 public static void main(String[] args) { 2 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/lvbinbin/autowired/spring.xml"); 3 Person p1=(Person) context.getBean("person1"); 4 System.out.println(p1); 5 System.out.println("ac:"+p1.ac); 6 System.out.println("bf:"+p1.bf); 7 System.out.println("rl:"+p1.rl); 8 System.out.println("ap:"+p1.ap); 9 System.out.println("env:"+p1.env); 10 }
查看下输出:其实ResourceLoader、ApplicationEventPublisher都是ApplicationContext的具体对象,因为ApplicationContext实现了这些接口;
博客的最后,记录一个笨比的尝试:(下面的例子是Spring源码编译后改动,编译教程建议看Spring源码深度解析)
Autowired注解可以标注在 方法入参上,测试一下:
上例Person类简单改造下:注释掉 Pet属性上的Autowired,在方法入参中加上@Autowired;这里补充下:Autowired的注解的方法名不一定非要set这种形式的方法;
1 // @Autowired 2 private Pet pet; 3 4 public void test1(@Autowired Pet p) { 5 this.pet=p; 6 }
同样的测试用例:发现Pet属性并没有注入上去(如果可以注入上去望指教);
简单改造下,可以支持 单个参数的Autowired注入,多个参数的Autowired实现,我力有不逮;
AutowiredAnnotationBeanPostProcessor的 findAutowiredAnnotation方法简单改造下,如果入参是Method且没有注解标注,顺便检查下参数上是否有Autowired注解,没有再返回null,就可以简单实现单个参数上的Autowired功能吧
1 @Nullable 2 private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) { 3 if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local 4 for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { 5 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type); 6 if (attributes != null) { 7 return attributes; 8 } 9 } 10 }
return null; 11 }
改造添加几行代码后方法这样的:
1 @Nullable 2 private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) { 3 if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local 4 for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { 5 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type); 6 if (attributes != null) { 7 return attributes; 8 } 9 } 10 } 11 if(ao instanceof Method) { 12 Parameter[] parameters = ((Method) ao).getParameters(); 13 for (Parameter parameter : parameters) { 14 for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { 15 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(parameter, type); 16 if (attributes != null) { 17 return attributes; 18 } 19 } 20 } 21 } 22 return null; 23 }
同样的我们再测试下:发现已经可以实现了Autowired单个属性的注入,多个属性的改造量太大,可以(wo)但(bu)没必要(hui);