说起spring的注入,可能大家都有了解。可你认知几种注入方式呢?你所认知的注入方式是否正确呢?我估计大多数人了解注入方式不全面,并且还会曲解一些概念。今天我们就参考最权威的官网来具体谈谈spring的注入方式。
这里想给大家复习一下Spring的基础知识,对于后续理解有很大帮助
想必关于这两个概念大家不会陌生,面试题经常会出现的。这里我们就从官网详细文档看一看。
详细的翻译具体概念我就不讲了,在这我只说出自己的理解
其实IOC也被称为DI,因为在spring中IOC作用就是不需要程序员来手动创建和管理JAVA类,而是由spring容器自动实例化Bean对象。怎么个IOC呢,其实就是通过DI(依赖注入)实现的。
补充一点关于spring的bean对象(后面简称bean)
其实bean对象就是java对象,不同的在于Bean对象是由spring创建管理对象。
bean对象 是 java对象,但java对象 不一定是 bean对象
我们的业务类,经过spring容器DI添加源数据从而生成一个Bean对象可以被使用。这也就是spring IOC容器的运行流程图。
关于配置元数据,spring官方文档给出了三种配置方式
虽说三种,但其实我接触也只有前两种。本文也是关于前两种详细介绍。
xml手动配置bean (自动装配可以通过set方法自动创建pojo类对象加上元数据信息构造成bean对象)
基于 XML 的 bean 注入方式的实现有三种方法:
在基于 XML 的 bean 装配中,我们需要了解一下自动注入模型
关于自动模型官网上解释说:当使用基于xml的注入方式时,可以指定自动连接模式
也就是说spring 的自动注入的模型 (仅仅针对xml-based配置)
使用java,annotation另外两种注入方式没有注入模型
@Autowired和@Resource两个注解实现。面试题中也经常会问到两个注解的区别,我搜索网上的答案却讲的是@Autowired是通过bytype,@Resource是通过byname。但这种理解显然是错误的,因为关于自动模型文章前面也已经说过 官网:当使用基于xml的注入方式时,可以指定自动连接模式
@Autowired和@Resource只不过是通过type,name去查找,而不是bytype以及byname模式。有什么区别?
区别在于byname通过名字找bean自动填充–>没找到就会报错
bytype通过类型去找bean自动填充–>没找到就会报错
1. @Autowired:type --> name --> error
不仅仅通过type找。type找不到,还可以通过name找。都找不到才会报错
spring包中的AutowiredAnnotationBeanPostProcessor.java中的一个方法实现解析的
2. @Resource:name --> type --> error
不仅仅通过name找。name找不到,还可以通过type找。都找不到才会报错
javax中的 commonAnnotationBeanPostProcessor.java中的一个方法实现解析的
这里再强调一下:
注解 无关注入的模型(no,byname,bytype,constract)
怎么说?还相信网上的知识点吗?不相信我说的?那可以我们还是来用code证明。
Appconfig.java
package services;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
@Configurable
@ComponentScan("com.shadow")
public class Appconfig {
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
}
}
其余都为空
GoudanService.java
package services;
public class GoudanService {
GouService gouService; public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
<property name="gouService">
<ref bean="gouBean"></ref>
</property>
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
}
}
运行Test.java的result
想要在GoudanService中配置GouService,我们采用xml配置方式的no注入模型。虽然我们没有配置注入模型参数但是xml默认是no。故所以我们运行Test.java得出结果是配置成功的。
我把xml这一段注释掉呢?
根据no注入模型的官网解释,大家应该知道这是无法自动配置的,也就是null。
GoudanService.java
package services;
public class GoudanService {
GouService gouService; public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
}
}
运行Test.java的result
我们发现bytype模型注入,与no方式注入想比不需要了bean里配置property的ref,spring容器会自动根据GouService的类型去找bean,结果找到了类型为:services.GouService的bean,所以也是可以配置成功的。
重点:bytype就是如果属性类型与bean的class类型相同那么可以自动配置,否则配置错误。看下面图
GoudanService.java
package services;
public class GoudanService {
GouService gouService; GouService gouBean; public GouService getGouBean() {
return gouBean;
} public void setGouBean(GouService gouBean) {
this.gouBean = gouBean;
} public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
// System.out.println(cc.getBean(GoudanService.class).getGouService());
System.out.println(cc.getBean(GoudanService.class).getGouBean());
}
}
运行Test.java的result
我们发现byname模型注入,与no方式注入想比不需要了bean里配置property的ref,spring容器会自动根据GouService定义属性名称去找bean的名称,结果找到了id名称为:gouBean的bean,所以也是可以配置成功的。
byname就是如果属性名称与bean的id名称相同那么可以自动配置,否则配置错误。
GoudanService.java
package services;
public class GoudanService {
GouService gouService;
GouService gouBean; //构造方法1
GoudanService(GouService gouBean){ this.gouBean=gouBean; }// //构造方法2
// GoudanService(GouService gouService){
// this.gouService=gouService;
// }
// //构造方法3
// GoudanService(GouService gouService,GouService gouBean){
// this.gouService=gouService;
// this.gouBean=gouBean;
// }
public GouService getGouBean() {
return gouBean;
}
public GouService getGouService() {
return gouService;
}
// public void setGouBean(GouService gouBean) {
// this.gouBean = gouBean;
// }
// public void setGouService(GouService gouService) {
// this.gouService = gouService;
// }
}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
System.out.println(cc.getBean(GoudanService.class).getGouBean());
}
}
分别运行构造方法1,2,3三次,注释掉其他两种构造方法
运行Test.java的result
构造方法1
构造方法2
构造方法3
我们发现construct模型注入,它既可以通过name注入也可以通过type注入。
在这里,很多人网上说@Autowired是通过bytype查找,但其实这种说法有些许的不严谨。
1.自动注入模型是基于xml的bean注入方式。
2.bytype模型是只要通过类型查找,如果找不到,或者找到两个相同的类型bean就会报错
3.而@Autowired是通过类型去找,找不到还会通过名称去找
而@Resource是通过byname查找,这种说法和@Autowired相似也是不严谨的。
byname模型是只要通过名称查找,如果找不到报错而@Resource是通过名称去找,找不到还会通过类型去找,不单单只限于通过name去查找。