Bean经常使用的装配方式有3种:java
在xml文件中配置Bean。spring
若是依赖不少,xml配置文件会很臃肿,后期维护、升级不方便。自动装配可解决这一问题。api
在<bean>中使用autowired属性完成依赖的自动装配,再也不使用<property>手动注入setter方法中的依赖,简化了配置,减小了xml中的代码量。数组
autowire属性的4个属性值:app
示例:函数
1 class Student{ 2 3 private String name; 4 5 public Student(String name){ 6 this.name=name; 7 } 8 9 public String getName(){ 10 return name; 11 } 12 } 13 14 15 class Teacher{ 16 private Student student; 17 18 public void setStudent(Student student) { 19 this.student = student; 20 } 21 22 public void say(){ 23 System.out.println(student.getName()+",叫家长来一下。"); 24 } 25 }
Teacher依赖于Student,依赖的对象要写成成员变量的形式。若是要使用自动装配,依赖对象的注入只能使用setter方式。测试
byName,name指的是setXxx()注入依赖的那个xxx,好比setStudent(Student student),name指的是student,将set后面的部分提出来,变成Camel写法。name不是指形参名的student。this
xml中的配置:spa
<bean id="student" class="my_package.Student"> <constructor-arg value="张三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="byName" />
第一个Bean是基于xml的普通装配,第二个Bean的配置是byName形式的自动装配。prototype
byName自动装配的执行过程:在这个Bean的定义中,找到setter方法,这里是setStudent(),其name是student(set后面部分提出来,变成Camel写法),根据这个name(student)找打到id/name是student的Bean实例,将这个实例自动注入。
因此对<bean>的id/name、setter方法的命名有严格要求。
本来是要用<property name ref="" />子元素注入依赖的,若是依赖较多,会写一大堆<property>子元素。自动装配,无论这个一Bean有多少个依赖,一句代码搞定,减小了代码量,由Spring容器自动注入依赖。但Spring容器要作更多的工做,装配速度会变慢。
说明:自动装配只能完成setter形式的依赖注入,不能完成构造器方式的依赖注入,且只能注入其它Bean,不能注入String、数组、集合等Java自带的类型。
测试代码:
1 public class Test { 2 public static void main(String[] args) { 3 ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); 4 Teacher teacher=applicationContext.getBean("teacher",Teacher.class); 5 teacher.say(); 6 } 7 }
运行,控制台打印出"张三,叫家长来一下。"。
根据要注入的Bean的类型来自动装配。
在上面的例子中,setStudent(Student student),要注入的依赖是Student类型的实例。
byType自动装配的执行过程:在这个Bean的定义中,找到setter方法,找到setter方法要注入的Bean的类型(Student),在Spring容器中找到Student类型的实例,注入。
若是Spring容器中该依赖有多个配置,好比:
<bean id="student" class="my_package.Student"> <constructor-arg value="张三" /> </bean> <bean id="student1" class="my_package.Student"> <constructor-arg value="李四" /> </bean>
它们都是Student这个Bean的配置,Spring容器不知道要注入的依赖是哪个,会报错,因此依赖的bean只能有一个配置。
这种是能够的:
<bean id="student" class="my_package.Student" scope="prototype">
<constructor-arg value="张三" />
</bean>
虽然Spring容器中可能有这个Bean的多个实例,但这些实例是同样的。
示例:
将byName示例中的xml中的配置修改以下便可
<bean id="student" class="my_package.Student"> <constructor-arg value="张三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="byType" />
1 class Student{ 2 public String getName(){ 3 return "张三"; 4 } 5 } 6 7 class Teacher{ 8 private Student student; 9 10 public Teacher(Student student){ 11 this.student=student; 12 } 13 14 public void say(){ 15 System.out.println(student.getName()+",叫家长来一下。"); 16 } 17 }
须要用构造器注入依赖,Spring容器会自动根据构造器中参数类型,用byType方式注入对应类型的依赖。
只能有一个构造器,不然Spring容器不知道使用哪一个构造器。
xml中的配置:
<bean id="student" class="my_package.Student" /> <bean id="teacher" class="my_package.Teacher" autowire="constructor" />
<?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" default-autowire="byName"> <bean id="student" class="my_package.Student"> <constructor-arg value="张三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="default" />
在<beans>中设置默认的自动装配方式,在须要使用自动装配的<bean>指定autowire="default",这样该<bean>使用的自动装配方式就是<beans>中设置的默认方式。
统一了应用的自动装配方式。
基于xml装配的方式,若是<bean>不少,xml文件依然很臃肿。基于注解的装配解决了这一问题。
基于注解的装配是最经常使用的。
Spring经常使用的注解:
记法:Autowired——Type,Qualifier——Name,ATQN。
1 class Student{ 2 private String name; 3 4 public Student(String name){ 5 this.name=name; 6 } 7 8 public String getName(){ 9 return name; 10 } 11 } 12 13 14 class Teacher{ 15 @Autowired 16 private Student student; 17 18 public void say(){ 19 System.out.println(student.getName()+",叫家长来一下。"); 20 } 21 }
没必要写setter方法,也没必要写构造器。在依赖的对象上添加@Autowired注解(固然也能够在setter方法上写),即按照类型自动装配依赖。
上面在Student类型的依赖上添加了@Autowired注解,会自动在Spring容器中,找到Student类型的Bean,注入。至关于byType。
xml中的配置:
<?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 https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <bean id="student" class="my_package.Student"> <constructor-arg value="张三" /> </bean> <bean id="teacher" class="my_package.Teacher"/> </beans>
基于注解的装配都须要用<context:annotation-config />开启注解装配,这句代码是告诉Spring容器,下面的这些bean使用的是注解装配。
<bean>中不使用autowire属性。
测试:
1 public class Test { 2 public static void main(String[] args) { 3 ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); 4 Teacher teacher=applicationContext.getBean("teacher",Teacher.class); 5 teacher.say(); 6 } 7 }
能够看到控制台打印出"张三,叫家长来一下。"。
修改Teacher类代码以下,其他不变。
1 class Teacher{ 2 @Autowired 3 @Qualifier(value="student") 4 private Student student; 5 6 public void say(){ 7 System.out.println(student.getName()+",叫家长来一下。"); 8 } 9 }
在依赖的Bean实例上添加@Qualifier,@Qualifier不能单独用,还须要添加@Autowired。
@Qualifier是byName方式的自动装配,须要用value指定依赖Bean的id/name,Spring容器根据这个value找到id/name为vBean,注入。
可简写为@Qualifier("student")。
1 class Teacher{ 2 @Resource(name = "student") 3 private Student student; 4 5 public void say(){ 6 System.out.println(student.getName()+",叫家长来一下。"); 7 } 8 }
先根据name找到Spring容器中name/id为student的Bean,注入。即优先以getName方式。
若是找不到name/id为指定值的Bean,或缺省name直接写@Resource,则以默认的getName方式:写在字段上默认name为成员变量名(student),写在setter方法上默认为set后面部分得Camel写法,好比setStudent()默认name为student。
若是仍是找不到依赖的Bean,则以byType方式注入。
说明
前3个是专用的,第四个是通用的。这些注解都只能在类(Bean)上使用。
示例
1 @Service 2 class Student{ 3 public String getName(){ 4 return "张三"; 5 } 6 } 7 8 @Service 9 class Teacher{ 10 @Resource(name = "student") 11 private Student student; 12 13 public void say(){ 14 System.out.println(student.getName()+",叫家长来一下。"); 15 } 16 }
xml中的配置:
<context:component-scan base-package="my_package" /> <bean id="student" class="my_package.Student" />
须要使用 <context:component-scan base-package="" />指定要扫描的包,这样会Spring容器会自动扫描指定的包,若是包中有上面4个注解,就将之装配为Bean。
<context:component-scan base-package="" />会自动开启注解,因此没必要再写<context:annotataion-config />。
其实上面4个注解的做用至关于<bean class="" />。
标注了这4个注解的类,Spring会自动在xml中把这个类配置为Bean,就是说在xml中没必要写<bean class="" />。
但只能是<bean class="" />这样基础的配置,若是要<constructor-arg>、<property>传递Java自带类型的参数,或其余Bean必须使用这个Bean的id/name(这个Bean要配置id/name),就不能省略该Bean的配置。
上面的例子中,Teacher类缺省了<bean class="my_package.Teacher" />。
@Resource(name = "student") private Student student;
Teacher类要用到Student类的id/name,因此Student类写了配置。
其实不写Student类的配置,则会使用byType方式向Teacher注入依赖,也能够。
<context:component-scan base-package="my_package" />这句代码不能缺省。
自动装配简化了配置,减小了代码量,但须要Spring容器作更多的工做,因此建立Bean的速度要慢一些。