一、装配Bean
1、介绍
在spring容器内拼凑bean叫做装配。装配bean的时候,需要告诉容器有哪些bean以及容器如何使用依赖注入将它们配合在一起。
使用XML装配,XML是最常见的spring应用系统配置源。几种spring容器都支持使用XML装配bean,包括:
XmlBeanFactory:调用ClassPathResource载入上下文定义文件(比如applicationContext.xml)。
ClassPathXmlApplicationContext:从类路径载入上下文定义文件。
XmlWebApplicationContext:从web应用上下文中载入定义文件。
2、实例化与销毁
spring实例化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法。
// 非注解的方式
1 <bean class="Foo" init-method="function-name" destory-method="function-name">
// 注解的方式
1 @PostConstruct public void init(){…} 2 @PreDestroy public void destroy(){…}
注意:注解的方式,bean只能扫描注入,不能与配置的方式混合用。且注解时步骤7、8顺序(bean的生命周期中的步骤)似乎有差别。
1 <bean class="...CommonAnnotationBeanPostProcessor">
spring也提供了两个接口来实现相同的功能:InitializingBean和DisposableBean,不推荐使用该接口,它将你的bean和springAPI邦定在一起,他们是一对。定制化是一对。
3、自动装配
Spring Ioc容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,可以自动让Spring通过检查BeanFactory中的内容来替我们指定bean的协作者。autowire的方便之处在减少或者消除属性或构造器参数的设置。
模式
|
描述
|
no
|
不自动装配
|
byName
|
根据属性名自动装配。检查容器并根据名字查找与属性名完全一致的bean,将其与属性自动装配。
|
byType
|
根据类型自动装配。检查容器中存在一个与指定属性类型相同的bean,将其与属性自动装配。
|
constructor
|
应用于构造参数。查找和bean的构造参数一致的一个或多个bean,若找不到或找到多个,抛异常。按照参数的类型装配。
|
autodetect
|
自动检测装配。先constructor后byType。
|
default
|
这个需要在
当在指定了default-atuowrite后,所有的bean的默认的autowire就是指定的装配方法。不写,则默认是defualt-autorwire=“no”
|
bean的autowire不写,即autowire="default",表明模式跟随default-atuowrite
bean的autowire指定,此时以bean的autowire为准。
若default-atuowrite不写,即default-atuowrite="no",表明不自动装配。
若default-atuowrite指定,所有的bean的默认的autowire就是指定的装配方法。
1 public class Master { 2 private String name; 3 private Dog myDog; 4 5 public Master() { 6 System.out.println("====Master()===="); 7 } 8 9 public Master(Dog dog) { 10 System.out.println("====Master(Dog dog)===="); 11 this.myDog = dog; 12 } 13 14 // getter && setter 15 } 16 17 public class Dog { 18 private String name; 19 private int age; 20 21 // getter && setter 22 } 23 24 application.xml 25 <?xml version="1.0" encoding="UTF-8" ?> 26 <beans xmlns="http://www.springframework.org/schema/beans" 27 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 28 xsi:schemaLocation="http://www.springframework.org/schema/beans 29 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd" 30 default-autowire="byName" 31 > 32 33 <bean id="master" class="com.lx.test8.Master"> 34 <property name="name" value="小明"/> 35 <!-- <property name="dog" ref="a"/> --> 36 </bean> 37 38 <bean id="myDog" class="com.lx.test8.Dog"> 39 <property name="name" value="大黄"/> 40 <property name="age" value="3"/> 41 </bean> 42 43 </beans> 44 45 public class Test { 46 public static void main(String[] args) { 47 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); 48 Master master = app.getBean(Master.class); 49 System.out.println(JSON.toJSONString(master)); 50 } 51 } 52 53 // ====Master()==== 54 // {"myDog":{"age":3,"name":"大黄"},"name":"小明"}
这里是按名字(id = 属性名)装配。其他情况修改测试一下即可。
二、DI
1、set方式注入
<bean>元素的<property>子元素指明了使用它们的set方法来注入。
1 public class Department { 2 private String name; 3 private String[] strArray; // 数组 4 private List<Employee> empList; // list集合 5 private Set<Employee> empSet; // set集合 6 private Map<String, Employee> empMap; // map集合 7 private Properties properties; // Properties的使用 8 private List<String> listStr; // list集合 9 10 // getter && setter 11 } 12 public class Employee { 13 private String name; 14 private int id; 15 16 // getter && setter 17 } 18 19 application.xml 20 21 <bean id="emp1" class="com.lx.spring.day1.Employee"> 22 <property name="name" value="张三"/> 23 <property name="id" value="20200001"/> 24 </bean> 25 26 <bean id="emp2" class="com.lx.spring.day1.Employee"> 27 <property name="name" value="李四"/> 28 <property name="id" value="20200002"/> 29 </bean> 30 31 <bean id="department" class="com.lx.spring.day1.Department"> 32 <property name="name" value="财务部"/> 33 <!-- <property name="name"><null/></property> 注入null--> 34 35 <!-- 给数组注入值 --> 36 <property name="strArray"> 37 <list> 38 <value>strArray1</value> 39 <value>strArray2</value> 40 <value>strArray3</value> 41 </list> 42 </property> 43 <!-- 给list注入值.有序 --> 44 <property name="empList"> 45 <list> 46 <ref bean="emp2"/> 47 <ref bean="emp1"/> 48 <ref bean="emp1"/> 49 <bean class="com.lx.spring.day1.Employee"> 50 <property name="name" value="配置的bean"/> 51 <property name="id" value="2020"/> 52 </bean> 53 </list> 54 </property> 55 <!-- 给set注入值.无序.不重复 --> 56 <property name="empSet"> 57 <set> 58 <ref bean="emp1"/> 59 <ref bean="emp2"/> 60 <ref bean="emp2"/> 61 </set> 62 </property> 63 <!-- 给map注入值. --> 64 <property name="empMap"> 65 <map> 66 <entry key="11" value-ref="emp1"/> 67 <entry key="22" value-ref="emp2"/> 68 <entry key="22" value-ref="emp1"/> 69 </map> 70 </property> 71 <!-- 给属性集合配置 --> 72 <property name="properties"> 73 <props> 74 <prop key="pp1">abcd</prop> 75 <prop key="pp2">hello</prop> 76 </props> 77 </property> 78 </bean> 79 80 public class Main { 81 public static void main(String[] args) { 82 ApplicationContext app = new ClassPathXmlApplicationContext("app1.xml"); 83 Department department = (Department) app.getBean("department"); 84 System.out.println(department.getName()); 85 86 System.out.println("-------取出strArray-------"); 87 for (String s : department.getStrArray()) { 88 System.out.println(s); 89 } 90 91 System.out.println("-------取出empList-------"); 92 for (Employee e : department.getEmpList()) { 93 System.out.println(e.toString()); 94 } 95 96 System.out.println("-------取出empSet-------"); 97 for (Employee e : department.getEmpSet()) { 98 System.out.println(e.toString()); 99 } 100 101 System.out.println("-------取出empMap-迭代器-------"); 102 Map<String, Employee> empMap = department.getEmpMap(); 103 Iterator<String> iterator = empMap.keySet().iterator(); 104 105 while (iterator.hasNext()) { 106 String key = iterator.next(); 107 Employee e = empMap.get(key); 108 System.out.println("key=" + key + " " + e.toString()); 109 } 110 111 System.out.println("-------取出empMap-for-------"); 112 for (Map.Entry<String, Employee> entry : department.getEmpMap().entrySet()) { 113 System.out.println("key=" + entry.getKey() + " " + entry.getValue().toString()); 114 } 115 116 System.out.println("-------取出properties-for-------"); 117 Properties properties = department.getProperties(); 118 for (Map.Entry<Object, Object> entry : properties.entrySet()) { 119 System.out.println("key=" + entry.getKey() + " " + entry.getValue()); 120 } 121 122 System.out.println("-------取出properties-Enumeration-------"); 123 Enumeration<Object> enumeration = properties.keys(); 124 while (enumeration.hasMoreElements()) { 125 String key = (String) enumeration.nextElement(); 126 System.out.println(key + " " + properties.getProperty(key)); 127 } 128 } 129 }
把集合注入部分提取出来
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 5 <!--1.引入名称空间 util--> 6 xmlns:util="http://www.springframework.org/schema/util" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 9 10 http://www.springframework.org/schema/util 11 http://www.springframework.org/schema/util/spring-util-4.3.xsd"> 12 13 <!--2.提取公共片段--> 14 <util:list id="partListStr"> 15 <value>易筋经</value> 16 <value>九阴真经</value> 17 <value>九阳神功</value> 18 </util:list> 19 20 <!--3.注入--> 21 <bean id="depart" class="com.lx.spring.day1.Department"> 22 <property name="listStr" ref="partListStr"/> 23 </bean> 24 25 </beans>
2、继承方式注入
1 // 父类 2 public class Person { 3 private String name; 4 private int age; 5 // getter && setter 6 } 7 8 public class Student extends Person { 9 private String degree; 10 // getter && setter 11 } 12 13 application.xml 14 <bean id="person" class="com.lx.test6.Person"> 15 <property name="name" value="人"/> 16 <property name="age" value="21"/> 17 </bean> 18 19 <bean id="student" parent="person" class="com.lx.test6.Student"> 20 <!-- 会覆盖从父类继承的属性 --> 21 <property name="name" value="小明"/> 22 <property name="degree" value="学士"/> 23 </bean> 24 25 public class Test { 26 public static void main(String[] args) { 27 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); 28 Student student = app.getBean(Student.class); 29 System.out.println(JSON.toJSONString(student)); 30 } 31 } 32 33 // {"age":21,"degree":"学士","name":"小明"}
3、构造器方式注入
1 public class Student { 2 private String name; 3 private int age; 4 5 public Student(String name, int age) { 6 this.name = name; 7 this.age = age; 8 } 9 // getter && setter 10 } 11 12 application.xml 13 <bean id="student" class="com.lx.test6.Student"> 14 <!-- 通过构造函数来注入属性值 --> 15 <constructor-arg index="0" type="java.lang.String" value="学生"/> 16 <constructor-arg index="1" type="int" value="22"/> 17 </bean> 18 19 public class Test { 20 public static void main(String[] args) { 21 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); 22 Student student = app.getBean(Student.class); 23 System.out.println(JSON.toJSONString(student)); 24 } 25 } 26 27 // {"age":22,"name":"学生"}
这种方式,set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不能实例化不完全的或无法使用的bean。
4、p名称空间方式注入(了解)
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 5 <!-- 1.添加p名称空间 --> 6 xmlns:p="http://www.springframework.org/schema/p" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> 9 10 <!-- 2.通过p名称空间方式注入属性值 --> 11 <bean id="t" class="com.lx.spring.day2.Teacher" p:name="张无忌" p:age="40"/> 12 13 </beans>
5、FactoryBean(工厂bean)
在配置文件定义bean类型可以和返回类型不一样。
1 public class MyBean implements FactoryBean<Teacher> { 2 3 // 定义返回bean 4 @Override 5 public Teacher getObject() throws Exception { 6 Teacher teacher = new Teacher(); 7 teacher.setAge(666); 8 teacher.setName("武天老师"); 9 return teacher; 10 } 11 12 @Override 13 public Class<?> getObjectType() { 14 return null; 15 } 16 17 @Override 18 public boolean isSingleton() { 19 return false; 20 } 21 }
1 <bean id="myBean" class="com.lx.spring.day4.MyBean"/>
1 // 测试类 2 public class Main { 3 public static void main(String[] args) { 4 ApplicationContext context = new ClassPathXmlApplicationContext("app4.xml"); 5 Teacher teacher = (Teacher) context.getBean("myBean"); 6 System.out.println(JSON.toJSONString(teacher)); 7 } 8 } 9 10 // 结果 11 {"age":666,"name":"武天老师"}
三、分散配置(引入属性文件)
代码示例:引入属性文件的两种方式
1 // db1.properties 2 name=db1 3 drivername=oracle 4 url=jdbc:oracle:thin:@127.0.0.1:1521: 5 pwd=123456 6 7 // application.xml 8 // 方式一 9 <context:property-placeholder location="classpath:db1.properties,classpath:db2.properties"/> 10 11 // 方式二 12 <bean id="configurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 13 <property name="locations"> 14 <list> 15 <value>classpath:db1.properties</value> 16 <value>classpath:db2.properties</value> 17 </list> 18 </property> 19 </bean> 20 21 <!-- $ 占位符获取属性变量的值 --> 22 <bean id="dBUtil1" class="com.lx.test8.DBUtil"> 23 <property name="name" value="${name}"/> 24 <property name="drivername" value="${drivername}"/> 25 <property name="url" value="${url}"/> 26 <property name="pwd" value="${pwd}"/> 27 </bean>