概述
"注入"的概念
本文讨论的"注入",指的是spring给Bean注入属性(也可以称之为"装配"),并非其他注入。
与"注入"相关的概念
配置spring容器有三种风格:xml、annotation和java config,当然也可以结合使用。其中java config风格注册的Bean由程序员自己管理,因此不在本文讨论范围之内。
spring给Bean注入属性有几种方式:通过构造器注入、通过属性的set方法注入、使用反射注入。
无论通过以上哪种方式进行注入,如果spring依赖程序员提供的配置信息,那么就是手动注入(也可以称之为"手动装配");如果spring不依赖任何配置信息,而是通过自动注入模型完成注入,那么就是自动注入(也可以称之为"自动装配"),因此spring注入策略可以分为以下四种:
- xml风格依赖配置信息完成注入
- xml风格使用自动注入模型完成注入
- annotation风格依赖配置信息完成注入
- annotation风格使用自动注入模型完成注入
xml风格依赖配置信息完成注入demo
public 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
// 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
@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风格使用自动注入模型完成注入
@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 对于注入的理解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复