Spring基础知识(4)- Spring Bean (一) | 简介、定义
在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 Bean。Bean 是一个由 Spring IoC 容器实例化、装配和管理的对象。
简而言之:
(1) Bean 是对象,一个或者多个不限定;
(2) Bean 由 Spring IoC 容器管理;
(3) Bean 是 Spring 应用程序的主要组成部分(或称为主要的功能模块);
IoC 容器通过获取 Java 类和该类相关的 Spring 配置元数据来进行实例化、装配和管理 Bean。
Spring 配置元数据一般包含如下信息:
(1) 如何创建一个 Bean;
(2) Bean 的作用域、生命周期等信息;
(3) Bean 的依赖关系、如何装配等信息;
Spring 的三种 Bean 配置方式:
(1) 基于配置文件 (XML格式、Properties格式) 的配置方式;
(2) 基于注解的配置方式;
(3) 基于Java配置(@Configuration)的配置方式;
即 Spring 配置元数据,可以在配置文件里,或在注解中。
1. 基于配置文件 (XML格式和Properties格式) 的配置方式
(1) Beans 配置文件 (主配置文件)
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-4.0.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-4.0.xsd" > 9 10 <bean id="man" class="com.example.Man"> 11 <!-- 构造函数注入 --> 12 <constructor-arg value="Spring constructor method" /> 13 14 <!-- setter 注入 --> 15 <property name="age" value="25"></property> 16 <property name="dependValue" value="Man set dependValue"></property> 17 18 </bean> 19 <bean id="person" class="com.example.Person"> 20 <!-- 构造函数注入 --> 21 <constructor-arg ref="man" type="com.example.Man"/> 22 23 <!-- 级联属性 setter 注入 --> 24 <property name="man.dependValue" value="Person set man.dependValue"></property> 25 26 <!-- setter 注入 Null, Empty 值 --> 27 <property name="nullValue"><null/></property> 28 <property name="emptyValue" value=""></property> 29 30 <!--使用 <![CDATA[]]> setter 注入特殊符号 --> 31 <property name="literalString"> 32 <value><![CDATA[<www.test.com>]]></value> 33 </property> 34 35 <!-- setter 注入集合<array>, <list>, <map>, <set> --> 36 <property name="array"> 37 <array> 38 <value>Array 1</value> 39 <value>Array 2</value> 40 <value>Array 3</value> 41 </array> 42 </property> 43 <property name="list"> 44 <list> 45 <value>List 1</value> 46 <value>List 2</value> 47 <value>List 3</value> 48 </list> 49 </property> 50 <property name="map"> 51 <map> 52 <entry key="1" value="Map 1"></entry> 53 <entry key="2" value="Map 2"></entry> 54 </map> 55 </property> 56 <property name="set"> 57 <set> 58 <value>Set 1</value> 59 <value>Set 2</value> 60 <value>Set 3</value> 61 </set> 62 </property> 63 64 </bean> 65 66 </beans>
上面的 <bean>标签就是用于配置 Bean 对象让 Spring 来创建的,<constructor-arg>标签就是告诉 Spring 使用构造函数注入,<property>标签就是告诉 Spring 使用 setter 注入。
Spring 可以通过 2 种方式实现属性注入:构造函数注入和 setter 注入(又称设值注入)。
*注:这里 Beans 配置文件保存为 spring-beans.xml,具体使用方式,参考 “Spring基础知识(2)- 创建 Spring 程序”,下同。
(2) 示例
1 package com.example; 2 3 import java.util.List; 4 import java.util.Map; 5 import java.util.Set; 6 import java.util.Arrays; 7 8 import org.springframework.context.support.ClassPathXmlApplicationContext; 9 import org.springframework.context.ApplicationContext; 10 11 public class App { 12 public static void main( String[] args ) { 13 ApplicationContext context1 = new ClassPathXmlApplicationContext("spring-beans.xml"); 14 Person person = (Person) context1.getBean("person"); 15 person.display(); 16 } 17 } 18 19 class Man { 20 String name; 21 int age; 22 private String dependValue; 23 24 // 有其它有参构造函数,所以不要省略 25 public Man() { 26 27 } 28 29 public Man(String name) { 30 this.name = name; 31 } 32 33 public void setDependValue(String dependValue) { 34 this.dependValue = dependValue; 35 } 36 37 public void display() { 38 System.out.println("Man -> display(): name = " + name 39 + ", age = " + age 40 + ", dependValue = " + dependValue); 41 } 42 43 public void setAge(int age) { 44 this.age = age; 45 } 46 } 47 48 class Person { 49 private Man man; 50 private String nullValue; 51 private String emptyValue; 52 private String literalString; 53 private String[] array; 54 private List<String> list; 55 private Map<String, String> map; 56 private Set<String> set; 57 58 // 有其它有参构造函数,所以不要省略 59 public Person() { 60 61 } 62 63 public Person(Man man) { 64 this.man = man; 65 } 66 67 // 使用级联属性 setter 注入,需提供一个依赖对象的 getXxx() 方法 68 public Man getMan() { 69 return man; 70 } 71 72 public void display() { 73 man.display(); 74 System.out.println("Person -> display(): nullValue = " + nullValue 75 + ", emptyValue = " + emptyValue 76 + ", literalString = " + literalString); 77 System.out.println("Person -> display(): array = " + Arrays.toString(array)); 78 System.out.println("Person -> display(): list = " + list); 79 System.out.println("Person -> display(): map = " + map); 80 System.out.println("Person -> display(): set = " + set); 81 } 82 83 public void setNullValue(String nullValue) { 84 this.nullValue = nullValue; 85 } 86 87 public void setEmptyValue(String emptyValue) { 88 this.emptyValue = emptyValue; 89 } 90 91 public void setLiteralString(String literalString) { 92 this.literalString = literalString; 93 } 94 95 public void setArray(String[] array) { 96 this.array = array; 97 } 98 99 public void setList(List<String> list) { 100 this.list = list; 101 } 102 103 public void setMap(Map<String, String> map) { 104 this.map = map; 105 } 106 107 public void setSet(Set<String> set) { 108 this.set = set; 109 } 110 }
2. 基于注解的配置方式
(1) Beans 配置文件 (主配置文件)
Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 <context:component-scan> 元素开启 Spring Beans的自动扫描功能。
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-4.0.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context-4.0.xsd" > 9 10 <context:component-scan base-package="com.example" /> 11 12 </beans>
添加 <context:component-scan> 标签,spring 就会去自动扫描 com.example 包内的 java 文件,如果扫描到文件中带有@Service, @Component, @Repository ,@Controller 等这些注解的类,则把这些类注册为 bean。
(2) 示例
1 package com.example; 2 3 import java.util.List; 4 import java.util.Map; 5 import java.util.Set; 6 import java.util.Arrays; 7 8 import javax.annotation.Resource; 9 import org.springframework.stereotype.Component; 10 import org.springframework.beans.factory.annotation.Value; 11 12 import org.springframework.context.support.ClassPathXmlApplicationContext; 13 import org.springframework.context.ApplicationContext; 14 15 public class App { 16 public static void main( String[] args ) { 17 ApplicationContext context1 = new ClassPathXmlApplicationContext("spring-beans.xml"); 18 Person2 person2 = (Person2) context1.getBean("person2"); 19 person2.display(); 20 } 21 } 22 23 @Component("man2") 24 class Man2 { 25 @Value("Spring setter method") 26 String name; 27 28 // 有其它有参构造函数,所以不要省略 29 public Man2() { 30 31 } 32 33 public Man2(String name) { 34 this.name = name; 35 } 36 37 public void display() { 38 System.out.println("Man2 -> display(): name = " + name); 39 } 40 } 41 42 @Component("person2") 43 class Person2 { 44 @Resource(name="man2") 45 private Man2 man2; 46 47 private String nullValue; 48 @Value("") 49 private String emptyValue; 50 @Value("<www.spring.com>") 51 private String literalString; 52 53 @Value("#{'1,2,3'.split(',')}") // #{} 是 SpEL 表达式语言 54 private String[] array; 55 @Value("#{'\"Java\",\"Spring\",\"Idea\"'.split(',')}") 56 private List<String> list; 57 @Value("#{'\"Tree\",\"Dog\",\"River\"'.split(',')}") 58 private Set<String> set; 59 @Value("#{{\"name\":\"Tester\",\"age\": 21}}") 60 private Map<String, String> map; 61 62 // 有其它有参构造函数,所以不要省略 63 public Person2() { 64 65 } 66 67 public Person2(Man2 man2) { 68 this.man2 = man2; 69 } 70 71 public void display() { 72 man2.display(); 73 System.out.println("Person2 -> display(): nullValue = " + nullValue 74 + ", emptyValue = " + emptyValue 75 + ", literalString = " + literalString); 76 System.out.println("Person2 -> display(): array = " + Arrays.toString(array)); 77 System.out.println("Person2 -> display(): list = " + list); 78 System.out.println("Person2 -> display(): set = " + set); 79 System.out.println("Person2 -> display(): map = " + map); 80 } 81 }
3. 基于Java配置(@Configuration)的配置方式
1) @Bean注解
Spring @Bean 是一个方法级别的注解,用于产生一个被 Spring IoC 容器所管理的 Bean。通常情况下,@Bean 可以与 @Configuration 和 @Component 注解一起使用。
在默认情况下 @Bean 注解所产生的 Bean 是单例模式的,此外,@Bean 还可以与 @Scope, @Lazy, @DependOn 和@Primary 注解一起使用。
属性 | 描述 |
name | 用于指定Bean的名称 |
value | name 的别名,效果等同于 name |
initMethod | 在初始化Bean实例时需要调用的方法名称。默认没有要调用的方法 |
destroyMethod | 在关闭应用上下文时要在Bean中调用的方法名称,默认不调用任何方法 |
autowireCandidate | 布尔类型,用于限定当前的Bean是否可以自动注入到其他Bean中,默认是true |
*注: initMethod、destroyMethod 指定的方法必须是不带参数的方法,且该方法允许在运行时抛出异常
2) @Configuration 和 @Bean 搭配使用
Spring 3.0 开始提供 @Configuration 注解用于定义配置类,可代替 XML 配置文件,被注解的类内部包含有一个或多个被 @Bean 注解的方法。
这些方法将会被 AnnotationConfigApplicationContext 或 AnnotationConfigWebApplicationContext 类进行扫描,并用于构建 bean 定义,初始化 Spring 容器。
示例:
1 package com.example; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 7 8 public class App { 9 public static void main( String[] args ) { 10 11 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ManualBeanConfig.class); 12 Forest forest = context.getBean(Forest.class); 13 forest.display(); 14 context.close(); 15 16 } 17 } 18 19 class Tree { 20 @Value("Tree name") 21 private String name; 22 23 public void setName(String name) { 24 this.name = name; 25 } 26 27 public void display() { 28 System.out.println("Tree -> display(): name = " + name); 29 } 30 } 31 32 class Forest { 33 @Value("Forest name") 34 private String name; 35 private Tree tree; 36 37 public void setTree(Tree tree) { 38 this.tree = tree; 39 } 40 41 public void setName(String name) { 42 this.name = name; 43 } 44 45 public void display() { 46 tree.display(); 47 System.out.println("Forest -> display(): name = " + name); 48 } 49 50 public void init() { 51 System.out.println("Forest -> init()"); 52 } 53 54 public void destroy() { 55 System.out.println("Forest -> destroy()"); 56 } 57 } 58 59 @Configuration 60 class ManualBeanConfig { 61 62 public ManualBeanConfig() { 63 System.out.println("ManualBeanConfig -> ManualBeanConfig()"); 64 } 65 66 @Bean 67 public Tree getTree() { 68 return new Tree(); 69 } 70 71 @Bean(initMethod = "init", destroyMethod = "destroy" ) 72 public Forest getForest() { 73 Forest forest = new Forest(); 74 forest.setTree(getTree()); 75 return forest; 76 } 77 }
输出:
ManualBeanConfig -> ManualBeanConfig()
Forest -> init()
Tree -> display(): name = Tree name
Forest -> display(): name = Forest name
Forest -> destroy()