Bean的装配可以理解为依赖注入,Bean的装配方式也就是Bean的依赖注入方式。装配方式有三种:基于XML的Bean装配、基于Annotation的Bean装配、自动装配。
1.Spring基于XML装配Bean
Spring 基于 XML 的装配通常采用两种实现方式,即设值注入和构造注入。
在 Spring 实例化 Bean 的过程中,首先会调用默认的构造方法实例化 Bean 对象,然后通过 Java 的反射机制调用 setXxx() 方法进行属性的注入。因此,设值注入要求一个 Bean 的对应类必须满足以下两点要求。
A.必须提供一个默认的无参构造方法。(当没有构造方法时,每个类默认都有一个无参)
B.必须为需要注入的属性提供对应的 setter 方法。
使用设值注入时,在 Spring 配置文件中,需要使用 <bean> 元素的子元素 <property> 元素为每个属性注入值。而使用构造注入时,在配置文件中,主要使用 <constructor-arg> 标签定义构造方法的参数,可以使用其 value 属性(或子元素)设置该参数的值。
1.1构造注入
构造函数注入:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myclass" class="com.weiwei.spring.MyClass">
<constructor-arg index="0" value="2"></constructor-arg>
<constructor-arg index="1" value="2.3"></constructor-arg>
<constructor-arg index="2" value="a"></constructor-arg>
<constructor-arg index="3" value="true"></constructor-arg>
</bean>
</beans>
public class MyClass {
//基本数据类型
private int intvalue;
private double doubvalue;
private char charvalue;
private Boolean boovalue;
public MyClass(){
}
public MyClass(int intvalue, double doubvalue, char charvalue, Boolean boovalue) {
this.intvalue = intvalue;
this.doubvalue = doubvalue;
this.charvalue = charvalue;
this.boovalue = boovalue;
}
public int getIntvalue() {
return intvalue;
}
public double getDoubvalue() {
return doubvalue;
}
public char getCharvalue() {
return charvalue;
}
public Boolean getBoovalue() {
return boovalue;
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
MyClass myclass = applicationContext.getBean("myclass", MyClass.class);
System.out.println("intvalue===="+myclass.getIntvalue());
System.out.println("doubvalue===="+myclass.getDoubvalue());
System.out.println("charvalue===="+myclass.getCharvalue());
System.out.println("boovalue===="+myclass.getBoovalue());
}
}
输出:
intvalue====2
doubvalue====2.3
charvalue====a
boovalue====true
基本数据类型构造函数注入演示到这,后面重点演示设置注入。
1.2 设值注入
package com.weiwei.spring.demo2;
import java.util.*;
public class MyClass {
//基本数据类型
private int intvalue;
private double doubvalue;
private char charvalue;
private Boolean boovalue;
//引用数据类型
private String strvalue;
//Date类型
private Date datevalue;
//对象类型
private Student student;
//String数组
private String[] strarray;
//对象类型数组
private Student[] stuarr;
//String类型集合
private List<String> strlist;
//对象类型集合
private List<Student> stulist;
//String类型set集合
private Set<String> strset;
//对象类型set集合
private Set<Student> stuset;
//String类型map集合
private Map<String,String> stringMap;
//对象类型map集合
private Map<String,Student> studentMap;
//properties
private Properties properties;
//提供getter和setter方法
public int getIntvalue() {
return intvalue;
}
public void setIntvalue(int intvalue) {
this.intvalue = intvalue;
}
public double getDoubvalue() {
return doubvalue;
}
public void setDoubvalue(double doubvalue) {
this.doubvalue = doubvalue;
}
public char getCharvalue() {
return charvalue;
}
public void setCharvalue(char charvalue) {
this.charvalue = charvalue;
}
public Boolean getBoovalue() {
return boovalue;
}
public void setBoovalue(Boolean boovalue) {
this.boovalue = boovalue;
}
public String getStrvalue() {
return strvalue;
}
public void setStrvalue(String strvalue) {
this.strvalue = strvalue;
}
public Date getDatevalue() {
return datevalue;
}
public void setDatevalue(Date datevalue) {
this.datevalue = datevalue;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String[] getStrarray() {
return strarray;
}
public void setStrarray(String[] strarray) {
this.strarray = strarray;
}
public Student[] getStuarr() {
return stuarr;
}
public void setStuarr(Student[] stuarr) {
this.stuarr = stuarr;
}
public List<String> getStrlist() {
return strlist;
}
public void setStrlist(List<String> strlist) {
this.strlist = strlist;
}
public List<Student> getStulist() {
return stulist;
}
public void setStulist(List<Student> stulist) {
this.stulist = stulist;
}
public Set<String> getStrset() {
return strset;
}
public void setStrset(Set<String> strset) {
this.strset = strset;
}
public Set<Student> getStuset() {
return stuset;
}
public void setStuset(Set<Student> stuset) {
this.stuset = stuset;
}
public Map<String, String> getStringMap() {
return stringMap;
}
public void setStringMap(Map<String, String> stringMap) {
this.stringMap = stringMap;
}
public Map<String, Student> getStudentMap() {
return studentMap;
}
public void setStudentMap(Map<String, Student> studentMap) {
this.studentMap = studentMap;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
package com.weiwei.spring.demo2;
public class Student {
private String stuaddress;
private String stuname;
public String getStuaddress() {
return stuaddress;
}
public void setStuaddress(String stuaddress) {
this.stuaddress = stuaddress;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
}
package com.weiwei.spring.demo2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
MyClass myclass = applicationContext.getBean("myclass", MyClass.class);
System.out.println("-----------基本数据类型--------------");
System.out.println("intvalue===="+myclass.getIntvalue());
System.out.println("doubvalue===="+myclass.getDoubvalue());
System.out.println("charvalue===="+myclass.getCharvalue());
System.out.println("boovalue===="+myclass.getBoovalue());
System.out.println("-----------引用数据类型--------------");
System.out.println("strvalue===="+myclass.getStrvalue());
System.out.println("datevalue===="+new SimpleDateFormat("yyyy-MM-dd").format(myclass.getDatevalue()));
System.out.println("student===="+myclass.getStudent().getStuaddress()+myclass.getStudent().getStuname());
System.out.println("-----------String类型数组--------------");
for (String strarr:myclass.getStrarray()) {
System.out.println(strarr);
}
System.out.println("-----------对象类型数组--------------");
for (Student student:myclass.getStuarr()) {
System.out.println(student.getStuname());
}
System.out.println("-----------String类型集合--------------");
for (String str1: myclass.getStrlist()) {
System.out.println(str1);
}
System.out.println("-----------对象类型集合--------------");
for (Student stu: myclass.getStulist()) {
System.out.println(stu.getStuname());
}
System.out.println("-----------String类型set集合--------------");
for (String strset:myclass.getStrset()){
System.out.println(strset);
}
System.out.println("-----------对象类型set集合--------------");
for (Student stuset:myclass.getStuset()) {
System.out.println(stuset.getStuname());
}
System.out.println("-----------String类型map集合--------------");
for (Map.Entry<String,String> entry:myclass.getStringMap().entrySet()) {
System.out.println(entry.getKey()+entry.getValue());
}
System.out.println("-----------对象map--------------");
for (Map.Entry<String,Student> entry:myclass.getStudentMap().entrySet()) {
System.out.println(entry.getKey()+entry.getValue().getStuaddress());
}
System.out.println("-----------properties--------------");
Properties properties = myclass.getProperties();
Set<String> stringSet = properties.stringPropertyNames();
for (String name:stringSet) {
System.out.println(name+"====="+properties.getProperty(name));
}
}
}
输出:
-----------基本数据类型--------------
intvalue====520
doubvalue====30.5
charvalue====a
boovalue====false
-----------引用数据类型--------------
strvalue====竞宝
datevalue====2022-03-03
student====西安劲爆
-----------String类型数组--------------
张三
李四
王五
-----------对象类型数组--------------
劲爆
搜索
-----------String类型集合--------------
java班
前端班
微信小程序
-----------对象类型集合--------------
劲爆
搜索
-----------String类型set集合--------------
set1
set2
set3
-----------对象类型set集合--------------
劲爆
搜索
-----------String类型map集合--------------
name张三
addrexs西安
work程序员
-----------对象map--------------
stu1西安
stu2重庆
-----------properties--------------
password=====123456
username=====root
2. Spring基于Annotation装配Bean
在 Spring 中,尽管使用 XML 配置文件可以实现 Bean 的装配工作,但如果应用中 Bean 的数量较多,会导致 XML 配置文件过于臃肿,从而给维护和升级带来一定的困难。
Java 从 JDK 5.0 以后,提供了 Annotation(注解)功能,Spring 也提供了对 Annotation 技术的全面支持。
使用前需要在配置文件中配置:自动扫描包中的注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置自动扫描包-->
<context:component-scan base-package="com.wangxing.demo1"></context:component-scan>
</beans>
Spring3 中定义了一系列的 Annotation(注解),常用的注解如下。
2.1 Component
(1)@Component
可以使用此注解描述Spring中的Bean【创建对象】,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。
@Component--默认使用@Component创建的Bean类的名称,首字母小写
@Component(name)--指定的名称
//@Component
@Component("stud") public class StudentBean {
public void testStudent(){
System.out.println("Stduent的实例方法");
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//StudentBean student = applicationContext.getBean("studentBean", StudentBean.class);
StudentBean student = applicationContext.getBean("stud", StudentBean.class);
student.testStudent();
}
}
2.2 Repository
(2)@Repository
用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Repository--默认使用@Repository创建的Bean类的名称,首字母小写
@Repository(name)--指定的名称
/**
* 数据访问层的操作类
*/
//@Component("studentDao")
@Repository("studentDaoImpl")
public class StudentDaoImpl {
public void insertStudent(){
System.out.println("数据访问层添加方法");
}
}
2.3 Service
(3) @Service
通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Service--默认使用@Service创建的Bean类的名称,首字母小写
@Service(name)--指定的名称
/**
* 业务访问层操作类
*/
//@Component("studentService")
@Service("studentServiceImpl")
public class StudentServiceImpl {
//@Autowired
@Resource
private StudentDaoImpl studentDao;
public void apperndStudent(){
System.out.println("业务访问层添加方法");
studentDao.insertStudent();
}
}
2.4 Controller
(4) @Controller
通常作用在控制层(如 Struts2 的 Action/SpringMVC的控制器类),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Controller--默认使用@Controller创建的Bean类的名称,首字母小写
@Controller(name)--指定的名称
/**
* 控制层操作类
*/
//@Component("studentController")
@Controller("studentController")
public class StudentController {
//@Autowired
@Resource
private StudentServiceImpl studentService;
public void addStudent(){
System.out.println("控制层添加方法");
studentService.apperndStudent();
}
}
2.5 Autowired
(5) @Autowired
默认按照 Bean 的类型进行装配依赖注入.
用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。
<context:component-scan base-package="com.weiwei.springdemo4.demo2"/>
@Component
public class StudentBean {
public String getString(){
return "竞宝";
}
}
@Component("per")
public class PersonBean {
@Autowired
// @Autowired可以把studentBean对象注入到person中
public StudentBean studentBean;
public void testPer(){
System.out.println("person的实例方法-------"+studentBean.getString());
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonBean per = applicationContext.getBean("per", PersonBean.class);
per.testPer();
}
}
2.6 Resource
(6) @Resource
其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。
@Resource 中有两个重要属性:name 和 type。
Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。
如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
@Component("student")
public class StudentBean {
public String getString(){
return "宝儿";
}
}
@Component("per")
public class PersonBean {
@Resource
// @Resource(name = "student") 如果指定name,就必须和创建好的对象的名称一样
// @Resource(type = StudentBean.class)
private StudentBean studentBean;
public void testPerson(){
System.out.println(studentBean.getString());
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonBean per = applicationContext.getBean("per", PersonBean.class);
per.testPerson();
}
}
@Autowired与@Resource有什么区别?
Autowired默认按照类型装配,而Resource默认按照实例名称装配,并且带有name属性和type属性,如果使用name属性,则必须按照实例名称装配,否则抛出异常,如果使用type属性,则必须按照类型装配,否则抛出异常,如果不使用属性,则先匹配实例名称,找不到再匹配类型,再找不到则抛出异常。
2.7 Qualifier
(7)@Qualifier
与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。
@Component("stss")
public class StudentBean {
public String getString(){
return "竞宝";
}
}
@Component("per")
public class PersonBean {
@Autowired
@Qualifier("stss")
// @Autowired可以把studentBean对象注入到person中
public StudentBean studentBean;
public void testPer(){
System.out.println("person的实例方法-------"+studentBean.getString());
}
}
3.Spring自动装配Bean
除了使用 XML 和 Annotation 的方式装配 Bean 以外,还有一种常用的装配方式——自动装配。自动装配就是指 Spring 容器可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。
要使用自动装配,就需要配置 <bean> 元素的 autowire 属性。autowire 属性有五个值,具体说明如表所示。
名称 | 说明 |
byName | 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。 |
byType | 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。 |
constructor | 根据构造方法的参数的数据类型,进行 byType 模式的自动装配。 |
autodetect | 如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。 |
no | 默认情况下,不使用自动装配,Bean 依赖必须通过 ref 元素定义。 |
Spring自动装配Bean
byName-----根据成员变量的name自动装配,如果类对象名称和另一个类中的成员变量的name相同,则自动装配
package com.wangxing.demo;
public class StudentBean {
public void testStudent(){
System.out.println("StudentBean的实例方法");
}
}
package com.wangxing.demo;
public class PersonBean {
private StudentBean studentBean;
public StudentBean getStudentBean() {
return studentBean;
}
public void setStudentBean(StudentBean studentBean) {
this.studentBean = studentBean;
}
public void testPerson(){
System.out.println("PersonBean类的实例方法");
studentBean.testStudent();
}
}
<bean id="studentBean" class="com.wangxing.demo.StudentBean"></bean>
<bean id="person" class="com.wangxing.demo.PersonBean" autowire="byName"></bean>
byType-----根据成员变量的数据类型自动装配,如果类的数据类型与另一个类中成据类型兼容,则自动装配。
package com.wangxing.demo;
public class StudentBean {
public void testStudent(){
System.out.println("StudentBean的实例方法");
}
}
package com.wangxing.demo;
public class PersonBean {
private StudentBean studentBean;
public StudentBean getStudentBean() {
return studentBean;
}
public void setStudentBean(StudentBean studentBean) {
this.studentBean = studentBean;
}
public void testPerson(){
System.out.println("PersonBean类的实例方法");
studentBean.testStudent();
}
}
<bean id="student" class="com.wangxing.demo.StudentBean"></bean>
<bean id="person" class="com.wangxing.demo.PersonBean" autowire="byType"></bean>
constructor--根据构造方法的参数的数据类型,进行byType模式的自动装配。
package com.wangxing.demo;
public class StudentBean {
public void testStudent(){
System.out.println("StudentBean的实例方法");
}
}
package com.wangxing.demo;
public class PersonBean {
private StudentBean studentBean;
public PersonBean(StudentBean studentBean){
this.studentBean=studentBean;
}
public void testPerson(){
System.out.println("PersonBean类的实例方法");
studentBean.testStudent();
}
}
<bean id="student" class="com.wangxing.demo.StudentBean"></bean>
<bean id="person" class="com.wangxing.demo.PersonBean" autowire="constructor"></bean>
autodetect---如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。
Spring3.0以后被淘汰
no---默认情况下,不使用自动装配,Bean 依赖必须通过 ref 元素定义。