前言:随着一个项目规模的增大,我们不得不引入许多Java bean对象,而这些对象一般来说是在Spring的配置文件applicationContext.xml中进行配置的,这样就声明了这是一个由Spring容器管理的bean对象。这种做法必然会导致Spring的配置文件的可读性很差。在Spring中,我们有一些小技巧可以避免这种情况。这就是本篇文章所讨论的。

 

一、定义bean的三种途径:

  • 首先编写Student和Teacher两个类

test/Student.java

1. public class Student {  
2.   
3. private String name;  
4.   
5. private Teacher teacher;  
6.   
7. public String getName() {  
8. return name;  
9.     }  
10.   
11. public void setName(String name) {  
12. this.name = name;  
13.     }  
14.   
15. public Teacher getTeacher() {  
16. return teacher;  
17.     }  
18.   
19. public void setTeacher(Teacher teacher) {  
20. this.teacher = teacher;  
21.     }  
22.   
23. }

test/Teacher.java

1. public class Teacher {  
2.   
3. private String name;  
4.   
5. public String getName() {  
6. return name;  
7.     }  
8.   
9. public void setName(String name) {  
10. this.name = name;  
11.     }  
12.   
13. }


  • 方法一:基于XML的bean定义(需要提供setter方法)


1. <?xml version="1.0" encoding="UTF-8"?>  
2. <beans xmlns="http://www.springframework.org/schema/beans"  
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
5.   
6. <bean id="student" class="test.Student">  
7. <property name="name" value="张三"/>  
8. <property name="teacher" ref="teacher"/>  
9. </bean>  
10.   
11. <bean id="teacher" class="test.Teacher">  
12. <property name="name" value="李四"/>  
13. </bean>  
14.   
15. </beans>


1. public class Main {  
2.   
3. public static void main(String args[]){  
4. new FileSystemXmlApplicationContext("applicationContext.xml的绝对路径");  
5. "student");  
6. "teacher");  
7. "学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());  
8. "老师的姓名:"+teacher.getName());  
9.     }  
10.   
11. }
  • 方法二:基于注解的bean定义(不需要提供setter方法)

Spring为此提供了四个注解,这些注解的作用与上面的XML定义bean效果一致,在于将组件交给Spring容器管理。组件的名称默认是类名(首字母变小写),也可以自己修改:

@Component:当对组件的层次难以定位的时候使用这个注解

@Controller:表示控制层的组件

@Service:表示业务逻辑层的组件

@Repository:表示数据访问层的组件

使用这些注解的时候还有一个地方需要注意,就是需要在applicationContext.xml中声明<contex:component-scan...>一项,指明Spring容器扫描组件的包目录。

1. @Component("teacher")  
2. public class Teacher {  
3.   
4. @Value("李四")  
5. private String name;  
6.   
7. public String getName() {  
8. return name;  
9.     }  
10.   
11. }

 

1. @Component("student")  
2. public class Student {  
3.   
4. @Value("张三")  
5. private String name;  
6.   
7. @Resource  
8. private Teacher teacher;  
9.   
10. public String getName() {  
11. return name;  
12.     }  
13.   
14. public Teacher getTeacher() {  
15. return teacher;  
16.     }  
17.   
18. }

 

1. <?xml version="1.0" encoding="UTF-8"?>  
2. <beans xmlns="http://www.springframework.org/schema/beans"  
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
4. xmlns:context="http://www.springframework.org/schema/context"  
5. xsi:schemaLocation="http://www.springframework.org/schema/beans  
6.        http://www.springframework.org/schema/beans/spring-beans.xsd  
7.        http://www.springframework.org/schema/context  
8. >  
9.   
10. <!--扫描组件的包目录-->  
11. <context:component-scan base-package="test"/>  
12.   
13. </beans>
1. public class Main {  
2.   
3. public static void main(String args[]){  
4. new FileSystemXmlApplicationContext("applicationContext.xml的绝对路径");  
5. "student");  
6. "teacher");  
7. "学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());  
8. "老师的姓名:"+teacher.getName());  
9.     }  
10.   
11. }
  • 方法三:基于Java类的bean定义(需要提供setter方法)

 

1. @Configuration  
2. public class BeansConfiguration {  
3.   
4. @Bean  
5. public Student student(){  
6. new Student();  
7. "张三");  
8.         student.setTeacher(teacher());  
9. return student;  
10.     }  
11.   
12. @Bean  
13. public Teacher teacher(){  
14. new Teacher();  
15. "李四");  
16. return teacher;  
17.     }  
18.   
19. }


1. public class Main {  
2.   
3. public static void main(String args[]){  
4. new AnnotationConfigApplicationContext(BeansConfiguration.class);  
5. "student");  
6. "teacher");  
7. "学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());  
8. "老师的姓名:"+teacher.getName());  
9.     }  
10.   
11. }



二、Spring的自动注入

  • Spring提供了五种自动装配的类型

no:顾名思义, 显式指明不使用Spring的自动装配功能

byName:根据属性和组件的名称匹配关系来实现bean的自动装配

byType:根据属性和组件的类型匹配关系来实现bean的自动装配,有多个适合类型的对象时装配失败

constructor:与byType类似是根据类型进行自动装配,但是要求待装配的bean有相应的构造函数

autodetect:利用Spring的自省机制判断使用byType或是constructor装配

 

 

  • 基于XML的自动装配


1. <?xml version="1.0" encoding="UTF-8"?>  
2. <beans xmlns="http://www.springframework.org/schema/beans"  
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
5. >  
6.   
7. <bean id="student" class="test.Student" autowire="byName">  
8. <property name="name" value="张三"/>  
9. </bean>  
10.   
11. <bean id="teacher" class="test.Teacher">  
12. <property name="name" value="李四"/>  
13. </bean>  
14.   
15. </beans>

这里我并没有显式为Student对象注入Teacher属性,而是使用autowired="byName"代替,这样一来Spring会帮我们处理这些细节,将名字是teacher的组件注入到Student对象中。

 

  • 基于注解的自动装配

其实上面已经应用过了,这里再提一下@Resource和@Autowired的区别。@Resource默认是使用byName进行装配,@Autowired默认使用byType进行装配。

 

1. @Component("teacher")  
2. public class Teacher {  
3.   
4. @Value("李四")  
5. private String name;  
6.   
7. public String getName() {  
8. return name;  
9.     }  
10.   
11. public void setName(String name) {  
12. this.name = name;  
13.     }  
14. }


1. @Component("student")  
2. public class Student {  
3.   
4. @Value("张三")  
5. private String name;  
6.   
7. @Resource  
8. private Teacher teacher;  
9.   
10. public String getName() {  
11. return name;  
12.     }  
13.   
14. public void setName(String name) {  
15. this.name = name;  
16.     }  
17.   
18. public Teacher getTeacher() {  
19. return teacher;  
20.     }  
21.   
22. public void setTeacher(Teacher teacher) {  
23. this.teacher = teacher;  
24.     }  
25. }



三、如何进行选择?

其实说了这么多,我们应该如何对这些不同方式进行权衡和选择呢?这个见仁见智,我说说我常用的方式。

  • 定义bean:一般我使用基于注解的bean定义。这样可以摆脱使用XML或是Java类对大量bean进行配置的噩梦,让程序变得简洁。注解还可以清楚地指明组件所在的层次。但是也有特殊的情况,比如说配置数据源,也许某个组件并不是你写的(来自于Spring或是第三方jar包里面的组件等),你没有办法在这些组件里面加上这些注解使之成为Spring容器管理的bean(别人也不会为你加上这些注解,因为他们不知道你会使用到哪些组件)。这种情况下就得使用XML或是Java类进行配置了,个人比较喜欢XML配置。如下例子:


1. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
2. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
3. <property name="url" value="jdbc:mysql://localhost:3306/study"/>  
4. <property name="username" value="账号"/>  
5. <property name="password" value="密码"/>  
6. </bean>


  • 自动装配:一般我使用基于注解的自动装配。同样也是为了减少XML配置文件的“篇幅”。
  • 通过使用基于注解的bean定义和自动装配,大大减少了XML配置文件的长度,增加了程序的可读性。