"注入"的概念
本文讨论的"注入",指的是spring给Bean注入属性(也可以称之为"装配"),并非其他注入。
与"注入"相关的概念
配置spring容器有三种风格:xml、annotation和java config,当然也可以结合使用。其中java config风格注册的Bean由程序员自己管理,因此不在本文讨论范围之内。
spring给Bean注入属性有几种方式:通过构造器注入、通过属性的set方法注入、使用反射注入。
无论通过以上哪种方式进行注入,如果spring依赖程序员提供的配置信息,那么就是手动注入(也可以称之为"手动装配");如果spring不依赖任何配置信息,而是通过自动注入模型完成注入,那么就是自动注入(也可以称之为"自动装配"),因此spring注入策略可以分为以下四种:
- xml风格依赖配置信息完成注入
- xml风格使用自动注入模型完成注入
- annotation风格依赖配置信息完成注入
- annotation风格使用自动注入模型完成注入
xml风格依赖配置信息完成注入demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45public class XmlBeanA { private XmlBeanB xmlBeanB; public XmlBeanB getXmlBeanB() { return xmlBeanB; } public void setXmlBeanB(XmlBeanB xmlBeanB) { this.xmlBeanB = xmlBeanB; } public XmlBeanA() { System.out.println("new XmlBeanA()"); } } public class XmlBeanB { public XmlBeanB() { System.out.println("new XmlBeanB()"); } } // xmlspringtest.xml <beans> <!--xml配置文件描述Bean之间的引用关系,让spring知道如何完成属性注入--> <bean id="xmlBeanA" class="com.tbryant.springtest.xmlspringtest.XmlBeanA"> <property name="xmlBeanB" ref="xmlBeanB"></property> </bean> <bean id="xmlBeanB" class="com.tbryant.springtest.xmlspringtest.XmlBeanB"> </bean> </beans> // 启动类 public class XmlApplication { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); context.setConfigLocation("classpath:xmlspringtest.xml"); context.refresh(); XmlBeanA beanA = (XmlBeanA) context.getBean("xmlBeanA"); XmlBeanB beanB = (XmlBeanB) context.getBean("xmlBeanB"); System.out.println(beanA); System.out.println(beanA.getXmlBeanB()); System.out.println(beanB); } }
运行结果
new XmlBeanA()
new XmlBeanB()
com.tbryant.springtest.xmlspringtest.XmlBeanA@59ec2012
com.tbryant.springtest.xmlspringtest.XmlBeanB@4cf777e8
com.tbryant.springtest.xmlspringtest.XmlBeanB@4cf777e8
xml风格使用自动注入模型完成注入demo
1
2
3
4
5
6
7
8
9// class XmlBeanA、class XmlBeanB和启动类同上 <beans default-autowire="byType"> <!--xml配置文件只注册Bean,无需描述Bean之间的引用关系--> <bean id="xmlBeanA" class="com.tbryant.springtest.xmlspringtest.XmlBeanA"> </bean> <bean id="xmlBeanB" class="com.tbryant.springtest.xmlspringtest.XmlBeanB"> </bean> </beans>
运行结果
new XmlBeanA()
new XmlBeanB()
com.tbryant.springtest.xmlspringtest.XmlBeanA@5cb9f472
com.tbryant.springtest.xmlspringtest.XmlBeanB@cb644e
com.tbryant.springtest.xmlspringtest.XmlBeanB@cb644e
annotation依赖配置信息完成注入demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39@Component public class AnnotationBeanA { @Autowired private AnnotationBeanB annotationBeanB; public AnnotationBeanB getAnnotationBeanB() { return annotationBeanB; } public AnnotationBeanA() { System.out.println("new AnnotationBeanA()"); } } @Component public class AnnotationBeanB { public AnnotationBeanB() { System.out.println("new AnnotationBeanB()"); } } // 配置文件 @ComponentScan("com.tbryant.springtest.annotationspringtest") public class AppConfig { } // 启动类 public class AnnotationApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); context.refresh(); AnnotationBeanA beanA = (AnnotationBeanA) context.getBean("annotationBeanA"); AnnotationBeanB beanB = (AnnotationBeanB) context.getBean("annotationBeanB"); System.out.println(beanA); System.out.println(beanA.getAnnotationBeanB()); System.out.println(beanB); } }
运行结果
new AnnotationBeanA()
new AnnotationBeanB()
com.tbryant.springtest.annotationspringtest.AnnotationBeanA@543c6f6d
com.tbryant.springtest.annotationspringtest.AnnotationBeanB@13eb8acf
com.tbryant.springtest.annotationspringtest.AnnotationBeanB@13eb8acf
注意:在AnnotationBeanA类的属性annotationBeanB上添加@Autowired注解,通过这种方式,告诉spring:这个属性需要你帮我注入。如果不加,spring就不会为这属性完成注入。回头再看xml风格使用自动注入模型完成注入demo,属性上无需添加任何注解,只需指定使用哪个自动注入模型,spring就能完成属性注入。
annotation风格使用自动注入模型完成注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54@Component public class AnnotationBeanA { // 无需@Autowired private AnnotationBeanB annotationBeanB; public AnnotationBeanB getAnnotationBeanB() { return annotationBeanB; } // 需要添加set方法 public void setAnnotationBeanB(AnnotationBeanB annotationBeanB) { this.annotationBeanB = annotationBeanB; } public AnnotationBeanA() { System.out.println("new AnnotationBeanA()"); } } @Component public class AnnotationBeanB { public AnnotationBeanB() { System.out.println("new AnnotationBeanB()"); } } // 配置文件 @ComponentScan("com.tbryant.springtest.annotationspringtest") public class AppConfig { } // 与xml风格相比,annotation风格只能针对某个Bean进行设置 @Component public class AnnotationBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { GenericBeanDefinition beanDefinitionA = (GenericBeanDefinition) beanFactory.getBeanDefinition("annotationBeanA"); beanDefinitionA.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); } } // 启动类 public class AnnotationApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); context.refresh(); AnnotationBeanA beanA = (AnnotationBeanA) context.getBean("annotationBeanA"); AnnotationBeanB beanB = (AnnotationBeanB) context.getBean("annotationBeanB"); System.out.println(beanA); System.out.println(beanA.getAnnotationBeanB()); System.out.println(beanB); } }
运行结果
new AnnotationBeanA()
new AnnotationBeanB()
com.tbryant.springtest.annotationspringtest.AnnotationBeanA@544a2ea6
com.tbryant.springtest.annotationspringtest.AnnotationBeanB@2e3fc542
com.tbryant.springtest.annotationspringtest.AnnotationBeanB@2e3fc542
个人理解
xml风格依赖配置信息完成注入是无自动化,相当于程序员明确指定哪个对象注入到哪个属性上,spring只是去完成注入这个动作。annotation依赖配置信息完成注入是半自动化,因为需要手动添加@Autowired,spring得知该属性需要注入后会读取属性的类型和名字,类似xml配置的标签;但因容器中可能存在多个该类型对象,spring会选择一个注入到属性上,所以还是有一些自动化的部分。使用自动注入模型是全自动化,指定使用哪种自动注入模型,spring就可以完成注入,无需对单个属性进行设置。
很多同学把@Autowired理解成自动注入,因为看字面意思就是自动注入,但spring的自动注入是使用自动注入模型实现的,@Autowired并没有使用四种自动注入模型的任意一种。
自动注入模型 vs @Autowired
自动注入模型在官方文档1.4.5. Autowiring Collaborators有介绍,一共有四种:no、byName、byType、constructor:
- no(不自动注入)
- byName(根据set方法名进行匹配,匹配不到就跳过,匹配到就注入)
- byType(根据set方法参数类型进行匹配,匹配不到就跳过;匹配到多个就报错)
- constructor(根据构造函数进行自动注入,这个自动注入模型涉及推断构造方法,默认选用参数最多的构造函数)
@Autowired逻辑如下:
- 根据属性类型匹配,匹配不到就报异常。
- 根据属性类型匹配,匹配到一个符合的对象,就注入。
- 根据属性类型匹配,匹配到多个符合的对象,再根据属性名进行匹配,匹配到就注入,匹配不到就报异常。
很多文章说@Autowired是先byType再byName,这个说法不完全正确,经过实验总结出以下几个不同点:
- 匹配依据不同:byType根据set方法参数类型进行匹配;@Autowired根据属性类型进行匹配。byName根据set方法名进行匹配,@Autowired根据属性名进行匹配。
- 匹配不到的处理方式不同:自动注入模型无论是byType还是byName匹配不到都会跳过;@Autowired匹配不到会报异常。
- 匹配到多个的处理方式不同:自动注入模型byType匹配到多个会报异常;@Autowired匹配到多个会再根据属性名进行匹配。
- 注入使用的技术不同:自动注入模型使用set方法进行注入;@Autowired使用field.set进行注入。
最后
以上就是狂野鸡最近收集整理的关于spring 对于注入的理解的全部内容,更多相关spring内容请搜索靠谱客的其他文章。
发表评论 取消回复